const struct set *set);
extern int set_to_intervals(struct list_head *msgs, struct set *set,
struct expr *init, bool add,
- unsigned int debug_mask);
+ unsigned int debug_mask, bool merge);
extern void interval_map_decompose(struct expr *set);
extern struct expr *mapping_expr_alloc(const struct location *loc,
* @octx: output context
* @debug_mask: display debugging information
* @cache: cache context
+ * @range_merge: merge adjacent/overlapping ranges in new set elements
*/
struct netlink_ctx {
struct mnl_socket *nf_sock;
unsigned int debug_mask;
struct output_ctx *octx;
struct nft_cache *cache;
+ bool range_merge;
};
extern struct nftnl_table *alloc_nftnl_table(const struct handle *h);
unsigned int debug_mask;
struct output_ctx output;
bool check;
+ bool range_merge;
struct nft_cache cache;
uint32_t flags;
};
ctx.nf_sock = nf_sock;
ctx.cache = &nft->cache;
ctx.debug_mask = nft->debug_mask;
+ ctx.range_merge = nft->range_merge;
init_list_head(&ctx.list);
ret = do_command(&ctx, cmd);
if (ret < 0)
set = set_lookup(table, h->set);
if (set->flags & NFT_SET_INTERVAL &&
- set_to_intervals(ctx->msgs, set, init, true, ctx->debug_mask) < 0)
+ set_to_intervals(ctx->msgs, set, init, true,
+ ctx->debug_mask, ctx->range_merge) < 0)
return -1;
return __do_add_setelems(ctx, h, set, init, flags);
if (set->init != NULL) {
if (set->flags & NFT_SET_INTERVAL &&
set_to_intervals(ctx->msgs, set, set->init, true,
- ctx->debug_mask) < 0)
+ ctx->debug_mask, ctx->range_merge) < 0)
return -1;
}
if (netlink_add_set(ctx, h, set, flags) < 0)
set = set_lookup(table, h->set);
if (set->flags & NFT_SET_INTERVAL &&
- set_to_intervals(ctx->msgs, set, expr, false, ctx->debug_mask) < 0)
+ set_to_intervals(ctx->msgs, set, expr, false,
+ ctx->debug_mask, ctx->range_merge) < 0)
return -1;
if (netlink_delete_setelems(ctx, h, expr) < 0)
return 0;
}
+static int intervals_overlap(struct list_head *msgs,
+ struct elementary_interval **intervals,
+ unsigned int keylen)
+{
+ unsigned int i, j;
+
+ for (i = 0; i < keylen - 1; i++) {
+ for (j = i + 1; j < keylen; j++) {
+ if (interval_overlap(intervals[i], intervals[j]))
+ return expr_error(msgs, intervals[j]->expr,
+ "interval overlaps with previous one");
+ }
+ }
+
+ return 0;
+}
+
static int set_to_segtree(struct list_head *msgs, struct set *set,
- struct expr *init, struct seg_tree *tree, bool add)
+ struct expr *init, struct seg_tree *tree,
+ bool add, bool merge)
{
struct elementary_interval *intervals[init->size];
struct expr *i, *next;
n = expr_to_intervals(init, tree->keylen, intervals);
+ if (add && !merge) {
+ err = intervals_overlap(msgs, intervals, n);
+ if (err < 0)
+ return err;
+ }
+
list_for_each_entry_safe(i, next, &init->expressions, list) {
list_del(&i->list);
expr_free(i);
static void segtree_linearize(struct list_head *list, const struct set *set,
const struct expr *init, struct seg_tree *tree,
- bool add)
+ bool add, bool merge)
{
bool needs_first_segment = segtree_needs_first_segment(set, init, add);
struct elementary_interval *ei, *nei, *prev = NULL;
mpz_sub_ui(q, ei->left, 1);
nei = ei_alloc(p, q, NULL, EI_F_INTERVAL_END);
list_add_tail(&nei->list, list);
- } else if (add && ei->expr->ops->type != EXPR_MAPPING) {
+ } else if (add && merge &&
+ ei->expr->ops->type != EXPR_MAPPING) {
/* Merge contiguous segments only in case of
* new additions.
*/
}
int set_to_intervals(struct list_head *errs, struct set *set,
- struct expr *init, bool add, unsigned int debug_mask)
+ struct expr *init, bool add, unsigned int debug_mask,
+ bool merge)
{
struct elementary_interval *ei, *next;
struct seg_tree tree;
LIST_HEAD(list);
seg_tree_init(&tree, set, init, debug_mask);
- if (set_to_segtree(errs, set, init, &tree, add) < 0)
+ if (set_to_segtree(errs, set, init, &tree, add, merge) < 0)
return -1;
- segtree_linearize(&list, set, init, &tree, add);
+ segtree_linearize(&list, set, init, &tree, add, merge);
init->size = 0;
list_for_each_entry_safe(ei, next, &list, list) {
meta length != 33-45;ok
meta length { 33, 55, 67, 88};ok
meta length { 33-55, 67-88};ok
-meta length { 33-55, 55-88, 100-120};ok;meta length { 33-88, 100-120}
+meta length { 33-55, 56-88, 100-120};ok;meta length { 33-55, 56-88, 100-120}
meta length != { 33, 55, 67, 88};ok
meta length { 33-55};ok
meta length != { 33-55};ok
[ byteorder reg 1 = hton(reg 1, 4, 4) ]
[ lookup reg 1 set __set%d ]
-# meta length { 33-55, 55-88, 100-120}
+# meta length { 33-55, 56-88, 100-120}
__set%d test-ip4 7
__set%d test-ip4 0
- element 00000000 : 1 [end] element 21000000 : 0 [end] element 59000000 : 1 [end] element 64000000 : 0 [end] element 79000000 : 1 [end]
+ element 00000000 : 1 [end] element 21000000 : 0 [end] element 38000000 : 0 [end] element 59000000 : 1 [end] element 64000000 : 0 [end] element 79000000 : 1 [end]
ip test-ip4 input
[ meta load len => reg 1 ]
[ byteorder reg 1 = hton(reg 1, 4, 4) ]
+++ /dev/null
-#!/bin/bash
-
-# This testscase checks the automerging of adjacent intervals
-
-set -e
-
-$NFT add table t
-$NFT add set t s { type ipv4_addr \; flags interval \; }
-$NFT add element t s { 192.168.0.0/24, 192.168.1.0/24 }
-$NFT list ruleset | grep "192.168.0.0/23" >/dev/null && exit 0
-echo "E: automerging of adjavect intervals failed in named set" >&2
-exit 1