]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
src: Add support for NFTNL_SET_DESC_CONCAT
authorStefano Brivio <sbrivio@redhat.com>
Thu, 30 Jan 2020 00:16:56 +0000 (01:16 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Fri, 7 Feb 2020 12:53:37 +0000 (13:53 +0100)
To support arbitrary range concatenations, the kernel needs to know
how long each field in the concatenation is. The new libnftnl
NFTNL_SET_DESC_CONCAT set attribute describes this as an array of
lengths, in bytes, of concatenated fields.

While evaluating concatenated expressions, export the datatype size
into the new field_len array, and hand the data over via libnftnl.

Similarly, when data is passed back from libnftnl, parse it into
the set description.

When set data is cloned, we now need to copy the additional fields
in set_clone(), too.

This change depends on the libnftnl patch with title:
  set: Add support for NFTA_SET_DESC_CONCAT attributes

v4: No changes
v3: Rework to use set description data instead of a stand-alone
    attribute
v2: No changes

Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/expression.h
include/rule.h
src/evaluate.c
src/mnl.c
src/netlink.c
src/rule.c

index b3e79c490b1ace52fa9af3fe07edc2470e3f1e06..6196be58c2a638a9649051ac5c24aad8acf7a9ee 100644 (file)
@@ -261,6 +261,8 @@ struct expr {
                        struct list_head        expressions;
                        unsigned int            size;
                        uint32_t                set_flags;
+                       uint8_t                 field_len[NFT_REG32_COUNT];
+                       uint8_t                 field_count;
                };
                struct {
                        /* EXPR_SET_REF */
index d5b31765612ececee3b6cd8fb9685bf78a61eea4..a7f106f715cffc0ac2e7625a3074fe2057f6c893 100644 (file)
@@ -289,7 +289,9 @@ extern struct rule *rule_lookup_by_index(const struct chain *chain,
  * @rg_cache:  cached range element (left)
  * @policy:    set mechanism policy
  * @automerge: merge adjacents and overlapping elements, if possible
- * @desc:      set mechanism desc
+ * @desc.size:         count of set elements
+ * @desc.field_len:    length of single concatenated fields, bytes
+ * @desc.field_count:  count of concatenated fields
  */
 struct set {
        struct list_head        list;
@@ -310,6 +312,8 @@ struct set {
        bool                    key_typeof_valid;
        struct {
                uint32_t        size;
+               uint8_t         field_len[NFT_REG32_COUNT];
+               uint8_t         field_count;
        } desc;
 };
 
index 09dd493f0757e337b5daf50ebda14ff6aa2500a3..55591f5f3526ad1d3d8caeb5b53ec32b98ae1b17 100644 (file)
@@ -1217,6 +1217,8 @@ static int expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr,
        struct expr *i, *next;
 
        list_for_each_entry_safe(i, next, &(*expr)->expressions, list) {
+               unsigned dsize_bytes;
+
                if (expr_is_constant(*expr) && dtype && off == 0)
                        return expr_binary_error(ctx->msgs, i, *expr,
                                                 "unexpected concat component, "
@@ -1241,6 +1243,9 @@ static int expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr,
                                                 i->dtype->name);
 
                ntype = concat_subtype_add(ntype, i->dtype->type);
+
+               dsize_bytes = div_round_up(i->dtype->size, BITS_PER_BYTE);
+               (*expr)->field_len[(*expr)->field_count++] = dsize_bytes;
        }
 
        (*expr)->flags |= flags;
@@ -3345,9 +3350,12 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set)
                        return set_key_data_error(ctx, set,
                                                  set->key->dtype, type);
        }
-       if (set->flags & NFT_SET_INTERVAL &&
-           set->key->etype == EXPR_CONCAT)
-               return set_error(ctx, set, "concatenated types not supported in interval sets");
+
+       if (set->flags & NFT_SET_INTERVAL && set->key->etype == EXPR_CONCAT) {
+               memcpy(&set->desc.field_len, &set->key->field_len,
+                      sizeof(set->desc.field_len));
+               set->desc.field_count = set->key->field_count;
+       }
 
        if (set_is_datamap(set->flags)) {
                if (set->data == NULL)
index d5bdff293c6189a86cce955e0fa89b3c2c2f7f54..340380ba6fef19082ddcaa58eaa65c090f07bcdf 100644 (file)
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -905,6 +905,13 @@ int mnl_nft_set_add(struct netlink_ctx *ctx, const struct cmd *cmd,
        if (set->data)
                set_key_expression(ctx, set->data, set->flags, udbuf, NFTNL_UDATA_SET_DATA_TYPEOF);
 
+       if (set->desc.field_len[0]) {
+               nftnl_set_set_data(nls, NFTNL_SET_DESC_CONCAT,
+                                  set->desc.field_len,
+                                  set->desc.field_count *
+                                  sizeof(set->desc.field_len[0]));
+       }
+
        nftnl_set_set_data(nls, NFTNL_SET_USERDATA, nftnl_udata_buf_data(udbuf),
                           nftnl_udata_buf_len(udbuf));
        nftnl_udata_buf_free(udbuf);
index a9ccebaf8efd5f0dcc3f07264420062412059b2c..791943b4d926c320627661ca86fa75037b025f79 100644 (file)
@@ -773,6 +773,17 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
        if (nftnl_set_is_set(nls, NFTNL_SET_DESC_SIZE))
                set->desc.size = nftnl_set_get_u32(nls, NFTNL_SET_DESC_SIZE);
 
+       if (nftnl_set_is_set(nls, NFTNL_SET_DESC_CONCAT)) {
+               uint32_t len = NFT_REG32_COUNT;
+               const uint8_t *data;
+
+               data = nftnl_set_get_data(nls, NFTNL_SET_DESC_CONCAT, &len);
+               if (data) {
+                       memcpy(set->desc.field_len, data, len);
+                       set->desc.field_count = len;
+               }
+       }
+
        return set;
 }
 
index 883b070720259695751ccfca0d9711e6df922aaf..4853c4f302ee8ae5dec8e16d869138fff9269374 100644 (file)
@@ -337,7 +337,7 @@ struct set *set_clone(const struct set *set)
        new_set->objtype        = set->objtype;
        new_set->policy         = set->policy;
        new_set->automerge      = set->automerge;
-       new_set->desc.size      = set->desc.size;
+       new_set->desc           = set->desc;
 
        return new_set;
 }