]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
evaluate: translate meter into dynamic set
authorPablo Neira Ayuso <pablo@netfilter.org>
Wed, 6 Mar 2024 16:48:58 +0000 (17:48 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Tue, 12 Mar 2024 22:35:33 +0000 (23:35 +0100)
129f9d153279 ("nft: migrate man page examples with `meter` directive to
sets") already replaced meters by dynamic sets.

This patch removes NFT_SET_ANONYMOUS flag from the implicit set that is
instantiated via meter, so the listing shows a dynamic set instead which
is the recommended approach these days.

Therefore, a batch like this:

 add table t
 add chain t c
 add rule t c tcp dport 80 meter m size 128 { ip saddr timeout 1s limit rate 10/second }

gets translated to a dynamic set:

 table ip t {
        set m {
                type ipv4_addr
                size 128
                flags dynamic,timeout
        }

        chain c {
                tcp dport 80 update @m { ip saddr timeout 1s limit rate 10/second burst 5 packets }
        }
 }

Check for NFT_SET_ANONYMOUS flag is also relaxed for list and flush
meter commands:

 # nft list meter ip t m
 table ip t {
        set m {
                type ipv4_addr
                size 128
                flags dynamic,timeout
        }
 }
 # nft flush meter ip t m

As a side effect the legacy 'list meter' and 'flush meter' commands allow
to flush a dynamic set to retain backward compatibility.

This patch updates testcases/sets/0022type_selective_flush_0 and
testcases/sets/0038meter_list_0 as well as the json output which now
uses the dynamic set representation.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/rule.h
src/evaluate.c
src/rule.c
tests/shell/testcases/sets/0022type_selective_flush_0
tests/shell/testcases/sets/0038meter_list_0
tests/shell/testcases/sets/dumps/0022type_selective_flush_0.json-nft
tests/shell/testcases/sets/dumps/0022type_selective_flush_0.nft
tests/shell/testcases/sets/dumps/0038meter_list_0.json-nft
tests/shell/testcases/sets/dumps/0038meter_list_0.nft

index 6835fe0691653a7820b64b3c88a7ff313d9b0f57..56a9495d46b0ec04e39486f89586c5ae0d67505f 100644 (file)
@@ -409,6 +409,11 @@ static inline bool set_is_meter(uint32_t set_flags)
        return set_is_anonymous(set_flags) && (set_flags & NFT_SET_EVAL);
 }
 
+static inline bool set_is_meter_compat(uint32_t set_flags)
+{
+       return set_flags & NFT_SET_EVAL;
+}
+
 static inline bool set_is_interval(uint32_t set_flags)
 {
        return set_flags & NFT_SET_INTERVAL;
index f8b8530c4b32043b8b842ee7592870bb01123aa7..bc8ddc040a5828b39b9b83c045c452e826fc7f93 100644 (file)
@@ -116,7 +116,8 @@ static struct expr *implicit_set_declaration(struct eval_ctx *ctx,
                                             const char *name,
                                             struct expr *key,
                                             struct expr *data,
-                                            struct expr *expr)
+                                            struct expr *expr,
+                                            uint32_t flags)
 {
        struct cmd *cmd;
        struct set *set;
@@ -126,13 +127,15 @@ static struct expr *implicit_set_declaration(struct eval_ctx *ctx,
                key_fix_dtype_byteorder(key);
 
        set = set_alloc(&expr->location);
-       set->flags      = NFT_SET_ANONYMOUS | expr->set_flags;
+       set->flags      = expr->set_flags | flags;
        set->handle.set.name = xstrdup(name);
        set->key        = key;
        set->data       = data;
        set->init       = expr;
        set->automerge  = set->flags & NFT_SET_INTERVAL;
 
+       handle_merge(&set->handle, &ctx->cmd->handle);
+
        if (set_evaluate(ctx, set) < 0) {
                if (set->flags & NFT_SET_MAP)
                        set->init = NULL;
@@ -143,7 +146,6 @@ static struct expr *implicit_set_declaration(struct eval_ctx *ctx,
        if (ctx->table != NULL)
                list_add_tail(&set->list, &ctx->table->sets);
        else {
-               handle_merge(&set->handle, &ctx->cmd->handle);
                memset(&h, 0, sizeof(h));
                handle_merge(&h, &set->handle);
                h.set.location = expr->location;
@@ -2088,7 +2090,8 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
 
                mappings = implicit_set_declaration(ctx, "__map%d",
                                                    key, data,
-                                                   mappings);
+                                                   mappings,
+                                                   NFT_SET_ANONYMOUS);
                if (!mappings)
                        return -1;
 
@@ -2661,7 +2664,8 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr)
                        right = rel->right =
                                implicit_set_declaration(ctx, "__set%d",
                                                         expr_get(left), NULL,
-                                                        right);
+                                                        right,
+                                                        NFT_SET_ANONYMOUS);
                        if (!right)
                                return -1;
 
@@ -3311,7 +3315,7 @@ static int stmt_evaluate_meter(struct eval_ctx *ctx, struct stmt *stmt)
                set->set_flags |= NFT_SET_TIMEOUT;
 
        setref = implicit_set_declaration(ctx, stmt->meter.name,
-                                         expr_get(key), NULL, set);
+                                         expr_get(key), NULL, set, 0);
        if (!setref)
                return -1;
 
@@ -4579,7 +4583,8 @@ static int stmt_evaluate_objref_map(struct eval_ctx *ctx, struct stmt *stmt)
                                          ctx->ectx.len, NULL);
 
                mappings = implicit_set_declaration(ctx, "__objmap%d",
-                                                   key, NULL, mappings);
+                                                   key, NULL, mappings,
+                                                   NFT_SET_ANONYMOUS);
                if (!mappings)
                        return -1;
                mappings->set->objtype  = stmt->objref.type;
@@ -5707,7 +5712,7 @@ static int cmd_evaluate_list(struct eval_ctx *ctx, struct cmd *cmd)
                                             ctx->cmd->handle.set.name);
                if ((cmd->obj == CMD_OBJ_SET && !set_is_literal(set->flags)) ||
                    (cmd->obj == CMD_OBJ_MAP && !map_is_literal(set->flags)) ||
-                   (cmd->obj == CMD_OBJ_METER && !set_is_meter(set->flags)))
+                   (cmd->obj == CMD_OBJ_METER && !set_is_meter_compat(set->flags)))
                        return cmd_error(ctx, &ctx->cmd->handle.set.location,
                                         "%s", strerror(ENOENT));
 
@@ -5886,7 +5891,7 @@ static int cmd_evaluate_flush(struct eval_ctx *ctx, struct cmd *cmd)
                if (set == NULL)
                        return set_not_found(ctx, &ctx->cmd->handle.set.location,
                                             ctx->cmd->handle.set.name);
-               else if (!set_is_meter(set->flags))
+               else if (!set_is_meter_compat(set->flags))
                        return cmd_error(ctx, &ctx->cmd->handle.set.location,
                                         "%s", strerror(ENOENT));
 
index adab584e9a792168c026d4a4b48ca946dc0cb33b..9e418d8c2f2f662ef4c25e2d3c50f2188e249d9b 100644 (file)
@@ -1613,7 +1613,7 @@ static int do_list_sets(struct netlink_ctx *ctx, struct cmd *cmd)
                            !set_is_literal(set->flags))
                                continue;
                        if (cmd->obj == CMD_OBJ_METERS &&
-                           !set_is_meter(set->flags))
+                           !set_is_meter_compat(set->flags))
                                continue;
                        if (cmd->obj == CMD_OBJ_MAPS &&
                            !map_is_literal(set->flags))
index 6062913b52729a16581fce98fdd39d75d3fe3b2d..48f6875bf459fda9dd10e11c90f3381dfdf4c36d 100755 (executable)
@@ -16,7 +16,7 @@ $NFT -f - <<< "$RULESET"
 # Commands that should be invalid
 
 declare -a cmds=(
-               "flush set t m" "flush set t f"
+               "flush set t m"
                "flush map t s" "flush map t f"
                "flush meter t s" "flush meter t m"
                )
index e9e0f6fb02b14f28779b902f8b6f84232afea5df..7c37c1d81131bb90eb4721c85c33b9a77d00885b 100755 (executable)
@@ -14,7 +14,12 @@ RULESET="
 "
 
 expected_output="table ip t {
-       meter m {
+       set s {
+               type ipv4_addr
+               size 256
+               flags dynamic,timeout
+       }
+       set m {
                type ipv4_addr
                size 128
                flags dynamic
index c82c12a171a54a07a3748666735dc686b372cd6e..c6281ae86c39b78d8db561587a43037943f59cb6 100644 (file)
         "map": "inet_service"
       }
     },
+    {
+      "set": {
+        "family": "ip",
+        "name": "f",
+        "table": "t",
+        "type": "ipv4_addr",
+        "handle": 0,
+        "size": 1024,
+        "flags": [
+          "dynamic"
+        ]
+      }
+    },
     {
       "chain": {
         "family": "ip",
             }
           },
           {
-            "meter": {
-              "key": {
+            "set": {
+              "op": "add",
+              "elem": {
                 "payload": {
                   "protocol": "ip",
                   "field": "saddr"
                 }
               },
-              "stmt": {
-                "limit": {
-                  "rate": 10,
-                  "burst": 5,
-                  "per": "second"
+              "set": "@f",
+              "stmt": [
+                {
+                  "limit": {
+                    "rate": 10,
+                    "burst": 5,
+                    "per": "second"
+                  }
                 }
-              },
-              "size": 1024,
-              "name": "f"
+              ]
             }
           }
         ]
index 0a4cb0a54d73030ba46eb4d687c2cd78667e0485..38987ded39e0d3699bb2d94047c594d523b641e4 100644 (file)
@@ -7,7 +7,13 @@ table ip t {
                type ipv4_addr : inet_service
        }
 
+       set f {
+               type ipv4_addr
+               size 1024
+               flags dynamic
+       }
+
        chain c {
-               tcp dport 80 meter f size 1024 { ip saddr limit rate 10/second burst 5 packets }
+               tcp dport 80 add @f { ip saddr limit rate 10/second burst 5 packets }
        }
 }
index be24687c96d79857c292a6f45e025d7f7ba3faa4..853fb5e35a144d46fd625e5efc1dd25d17701f8f 100644 (file)
         ]
       }
     },
+    {
+      "set": {
+        "family": "ip",
+        "name": "m",
+        "table": "t",
+        "type": "ipv4_addr",
+        "handle": 0,
+        "size": 128,
+        "flags": [
+          "dynamic"
+        ]
+      }
+    },
     {
       "chain": {
         "family": "ip",
             }
           },
           {
-            "meter": {
-              "key": {
+            "set": {
+              "op": "add",
+              "elem": {
                 "payload": {
                   "protocol": "ip",
                   "field": "saddr"
                 }
               },
-              "stmt": {
-                "limit": {
-                  "rate": 10,
-                  "burst": 5,
-                  "per": "second"
+              "set": "@m",
+              "stmt": [
+                {
+                  "limit": {
+                    "rate": 10,
+                    "burst": 5,
+                    "per": "second"
+                  }
                 }
-              },
-              "size": 128,
-              "name": "m"
+              ]
             }
           }
         ]
index f274086b5285431462f7651c00010cb90b23ab96..8037dfa502b4d491a31119ca1171bd31d2547c1a 100644 (file)
@@ -5,7 +5,13 @@ table ip t {
                flags dynamic,timeout
        }
 
+       set m {
+               type ipv4_addr
+               size 128
+               flags dynamic
+       }
+
        chain c {
-               tcp dport 80 meter m size 128 { ip saddr limit rate 10/second burst 5 packets }
+               tcp dport 80 add @m { ip saddr limit rate 10/second burst 5 packets }
        }
 }