summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/expression.h2
-rw-r--r--include/netlink.h2
-rw-r--r--include/nftables.h1
-rw-r--r--src/libnftables.c1
-rw-r--r--src/rule.c8
-rw-r--r--src/segtree.c38
-rw-r--r--tests/py/any/meta.t2
-rw-r--r--tests/py/any/meta.t.payload4
-rwxr-xr-xtests/shell/testcases/sets/0002named_interval_automerging_012
9 files changed, 45 insertions, 25 deletions
diff --git a/include/expression.h b/include/expression.h
index 915ce0ba..0a0e178f 100644
--- a/include/expression.h
+++ b/include/expression.h
@@ -419,7 +419,7 @@ extern struct expr *set_expr_alloc(const struct location *loc,
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,
diff --git a/include/netlink.h b/include/netlink.h
index 51cd5c9d..4ec215da 100644
--- a/include/netlink.h
+++ b/include/netlink.h
@@ -42,6 +42,7 @@ extern const struct location netlink_location;
* @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;
@@ -55,6 +56,7 @@ struct netlink_ctx {
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);
diff --git a/include/nftables.h b/include/nftables.h
index 3bfa33e5..f22df0d1 100644
--- a/include/nftables.h
+++ b/include/nftables.h
@@ -31,6 +31,7 @@ struct nft_ctx {
unsigned int debug_mask;
struct output_ctx output;
bool check;
+ bool range_merge;
struct nft_cache cache;
uint32_t flags;
};
diff --git a/src/libnftables.c b/src/libnftables.c
index c86d8947..8a18bb78 100644
--- a/src/libnftables.c
+++ b/src/libnftables.c
@@ -43,6 +43,7 @@ static int nft_netlink(struct nft_ctx *nft,
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)
diff --git a/src/rule.c b/src/rule.c
index bb9add07..edd0ff6f 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -997,7 +997,8 @@ static int do_add_setelems(struct netlink_ctx *ctx, const struct handle *h,
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);
@@ -1009,7 +1010,7 @@ static int do_add_set(struct netlink_ctx *ctx, const struct handle *h,
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)
@@ -1108,7 +1109,8 @@ static int do_delete_setelems(struct netlink_ctx *ctx, const struct handle *h,
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)
diff --git a/src/segtree.c b/src/segtree.c
index 8d36cc9b..d2c4efaa 100644
--- a/src/segtree.c
+++ b/src/segtree.c
@@ -375,8 +375,26 @@ static int set_overlap(struct list_head *msgs, const struct set *set,
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;
@@ -394,6 +412,12 @@ static int set_to_segtree(struct list_head *msgs, struct set *set,
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);
@@ -450,7 +474,7 @@ static bool segtree_needs_first_segment(const struct set *set,
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;
@@ -489,7 +513,8 @@ static void segtree_linearize(struct list_head *list, const struct set *set,
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.
*/
@@ -550,16 +575,17 @@ static void set_insert_interval(struct expr *set, struct seg_tree *tree,
}
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) {
diff --git a/tests/py/any/meta.t b/tests/py/any/meta.t
index a38c5011..3158e887 100644
--- a/tests/py/any/meta.t
+++ b/tests/py/any/meta.t
@@ -15,7 +15,7 @@ meta length 33-45;ok
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
diff --git a/tests/py/any/meta.t.payload b/tests/py/any/meta.t.payload
index b2065f3d..d0199b8a 100644
--- a/tests/py/any/meta.t.payload
+++ b/tests/py/any/meta.t.payload
@@ -52,10 +52,10 @@ ip test-ip4 input
[ 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) ]
diff --git a/tests/shell/testcases/sets/0002named_interval_automerging_0 b/tests/shell/testcases/sets/0002named_interval_automerging_0
deleted file mode 100755
index b07e0b09..00000000
--- a/tests/shell/testcases/sets/0002named_interval_automerging_0
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/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