From: Phil Sutter <phil@nwl.cc>
To: Stefano Brivio <sbrivio@redhat.com>
Cc: "Pablo Neira Ayuso" <pablo@netfilter.org>,
netfilter-devel@vger.kernel.org,
"Florian Westphal" <fw@strlen.de>,
"Kadlecsik József" <kadlec@blackhole.kfki.hu>,
"Eric Garver" <eric@garver.life>
Subject: Re: [PATCH nft 2/3] src: Add support for concatenated set ranges
Date: Tue, 19 Nov 2019 23:12:38 +0100 [thread overview]
Message-ID: <20191119221238.GF8016@orbyte.nwl.cc> (raw)
In-Reply-To: <20191119010712.39316-3-sbrivio@redhat.com>
Hi,
On Tue, Nov 19, 2019 at 02:07:11AM +0100, Stefano Brivio wrote:
[...]
> diff --git a/src/netlink.c b/src/netlink.c
> index 7306e358..b8bfd199 100644
> --- a/src/netlink.c
> +++ b/src/netlink.c
[...]
> @@ -199,10 +210,39 @@ static void netlink_gen_concat_data(const struct expr *expr,
> memset(data, 0, sizeof(data));
> offset = 0;
> list_for_each_entry(i, &expr->expressions, list) {
> - assert(i->etype == EXPR_VALUE);
> - mpz_export_data(data + offset, i->value, i->byteorder,
> - div_round_up(i->len, BITS_PER_BYTE));
> - offset += netlink_padded_len(i->len) / BITS_PER_BYTE;
> + if (i->etype == EXPR_RANGE) {
> + const struct expr *e;
> +
> + if (is_range_end)
> + e = i->right;
> + else
> + e = i->left;
> +
> + offset += netlink_export_pad(data + offset,
> + e->value, e);
> + } else if (i->etype == EXPR_PREFIX) {
> + if (is_range_end) {
> + mpz_t v;
> +
> + mpz_init_bitmask(v, i->len -
> + i->prefix_len);
> + mpz_add(v, i->prefix->value, v);
> + offset += netlink_export_pad(data +
> + offset,
> + v, i);
Given the right-alignment, maybe introduce __netlink_gen_concat_data()
to contain the loop body?
> + mpz_clear(v);
> + continue;
> + }
> +
> + offset += netlink_export_pad(data + offset,
> + i->prefix->value,
> + i);
> + } else {
> + assert(i->etype == EXPR_VALUE);
> +
> + offset += netlink_export_pad(data + offset,
> + i->value, i);
> + }
> }
>
> memcpy(nld->value, data, len);
> @@ -247,13 +287,14 @@ static void netlink_gen_verdict(const struct expr *expr,
> }
> }
>
> -void netlink_gen_data(const struct expr *expr, struct nft_data_linearize *data)
> +void netlink_gen_data(const struct expr *expr, struct nft_data_linearize *data,
> + int end)
s/end/is_range_end/ for consistency?
> {
> switch (expr->etype) {
> case EXPR_VALUE:
> return netlink_gen_constant_data(expr, data);
> case EXPR_CONCAT:
> - return netlink_gen_concat_data(expr, data);
> + return netlink_gen_concat_data(expr, data, end);
> case EXPR_VERDICT:
> return netlink_gen_verdict(expr, data);
> default:
> @@ -712,8 +753,14 @@ void alloc_setelem_cache(const struct expr *set, struct nftnl_set *nls)
> const struct expr *expr;
>
> list_for_each_entry(expr, &set->expressions, list) {
> - nlse = alloc_nftnl_setelem(set, expr);
> + nlse = alloc_nftnl_setelem(set, expr, 0);
> nftnl_set_elem_add(nls, nlse);
> +
> + if (set->set_flags & NFT_SET_SUBKEY) {
> + nlse = alloc_nftnl_setelem(set, expr, 1);
> + nftnl_set_elem_add(nls, nlse);
> + }
> +
Can't we drop 'const' from expr declaration and temporarily set
EXPR_F_INTERVAL_END to carry the is_interval_end bit or does that mess
up set element creation?
What I don't like about your code is how it adds an expression-type
specific parameter to netlink_gen_data which is supposed to be
type-agnostic. Avoiding this would also shrink this patch quite a bit.
[...]
> diff --git a/src/parser_bison.y b/src/parser_bison.y
> index 3f283256..2b718971 100644
> --- a/src/parser_bison.y
> +++ b/src/parser_bison.y
[...]
> @@ -3941,7 +3940,24 @@ basic_rhs_expr : inclusive_or_rhs_expr
> ;
>
> concat_rhs_expr : basic_rhs_expr
> - | concat_rhs_expr DOT basic_rhs_expr
> + | multiton_rhs_expr
> + | concat_rhs_expr DOT multiton_rhs_expr
> + {
> + if ($$->etype != EXPR_CONCAT) {
> + $$ = concat_expr_alloc(&@$);
> + compound_expr_add($$, $1);
> + } else {
> + struct location rhs[] = {
> + [1] = @2,
> + [2] = @3,
> + };
> + location_update(&$3->location, rhs, 2);
> + $$ = $1;
> + $$->location = @$;
> + }
> + compound_expr_add($$, $3);
> + }
> + | concat_rhs_expr DOT basic_rhs_expr
So this is the fifth copy of the same piece of code. :(
Isn't there a better way to solve that? If not, we could at least
introduce a function compound_expr_alloc_or_add().
[...]
> diff --git a/src/rule.c b/src/rule.c
> index 4abc13c9..377781b1 100644
> --- a/src/rule.c
> +++ b/src/rule.c
[...]
> @@ -1618,15 +1620,15 @@ static int do_command_insert(struct netlink_ctx *ctx, struct cmd *cmd)
>
> static int do_delete_setelems(struct netlink_ctx *ctx, struct cmd *cmd)
> {
> - struct handle *h = &cmd->handle;
> struct expr *expr = cmd->expr;
> + struct handle *h = &cmd->handle;
Unrelated change?
> struct table *table;
> struct set *set;
>
> table = table_lookup(h, &ctx->nft->cache);
> set = set_lookup(table, h->set.name);
>
> - if (set->flags & NFT_SET_INTERVAL &&
> + if (set->flags & NFT_SET_INTERVAL && !(set->flags & NFT_SET_SUBKEY) &&
Maybe introduce set_is_non_concat_range() or something? Maybe even a
macro, it's just about:
| return set->flags & (NFT_SET_INTERVAL | NFT_SET_SUBKEY) == NFT_SET_INTERVAL;
[...]
> diff --git a/src/segtree.c b/src/segtree.c
> index 9f1eecc0..e49576bc 100644
> --- a/src/segtree.c
> +++ b/src/segtree.c
[...]
> @@ -823,6 +828,9 @@ static int expr_value_cmp(const void *p1, const void *p2)
> struct expr *e2 = *(void * const *)p2;
> int ret;
>
> + if (expr_value(e1)->etype == EXPR_CONCAT)
> + return -1;
> +
Funny how misleading expr_value()'s name is. ;)
[...]
> +/* Given start and end elements of a range, check if it can be represented as
> + * a single netmask, and if so, how long, by returning a zero or positive value.
> + */
> +static int range_mask_len(mpz_t start, mpz_t end, unsigned int len)
> +{
> + unsigned int step = 0, i;
> + mpz_t base, tmp;
> + int masks = 0;
> +
> + mpz_init_set_ui(base, mpz_get_ui(start));
> +
> + while (mpz_cmp(base, end) <= 0) {
> + step = 0;
> + while (!mpz_tstbit(base, step)) {
> + mpz_init_set_ui(tmp, mpz_get_ui(base));
> + for (i = 0; i <= step; i++)
> + mpz_setbit(tmp, i);
> + if (mpz_cmp(tmp, end) > 0) {
> + mpz_clear(tmp);
> + break;
> + }
> + mpz_clear(tmp);
> +
> + step++;
> +
> + if (step >= len)
> + goto out;
> + }
> +
> + if (masks++)
> + goto out;
> +
> + mpz_add_ui(base, base, 1 << step);
> + }
> +
> +out:
> + mpz_clear(base);
> +
> + if (masks > 1)
> + return -1;
> + return len - step;
> +}
I don't understand this algorithm. Intuitively, I would just:
| int tmp = len;
| while (start != end && !(start & 1) && (end & 1) && tmp) {
| start >>= 1;
| end >>= 1;
| tmp--;
| }
| return (tmp && start == end) ? len - tmp : -1;
Is that slow when dealing with gmp?
Thanks, Phil
next prev parent reply other threads:[~2019-11-19 22:12 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-11-19 1:07 [PATCH nft 0/3] Introduce support for concatenated ranges Stefano Brivio
2019-11-19 1:07 ` [PATCH nft 1/3] src: Add support for and export NFT_SET_SUBKEY attributes Stefano Brivio
2019-11-19 1:07 ` [PATCH nft 2/3] src: Add support for concatenated set ranges Stefano Brivio
2019-11-19 22:12 ` Phil Sutter [this message]
2019-11-20 11:49 ` Stefano Brivio
2019-11-20 12:53 ` Phil Sutter
2019-11-21 17:09 ` Stefano Brivio
2019-11-21 17:58 ` Phil Sutter
2019-11-19 1:07 ` [PATCH nft 3/3] tests: Introduce test for set with concatenated ranges Stefano Brivio
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20191119221238.GF8016@orbyte.nwl.cc \
--to=phil@nwl.cc \
--cc=eric@garver.life \
--cc=fw@strlen.de \
--cc=kadlec@blackhole.kfki.hu \
--cc=netfilter-devel@vger.kernel.org \
--cc=pablo@netfilter.org \
--cc=sbrivio@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.