]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
netlink_linearize: reduce register waste with non-constant binop expressions
authorPablo Neira Ayuso <pablo@netfilter.org>
Mon, 10 Mar 2025 19:11:44 +0000 (20:11 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Mon, 10 Mar 2025 20:28:56 +0000 (21:28 +0100)
Register use is not good with bitwise operations that involve three or
more selectors, eg.

 mark set ip dscp and 0x3 or ct mark or meta mark
  [ payload load 1b @ network header + 1 => reg 1 ]
  [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
  [ bitwise reg 1 = ( reg 1 >> 0x00000002 ) ]
  [ bitwise reg 1 = ( reg 1 & 0x00000003 ) ^ 0x00000000 ]
  [ ct load mark => reg 2 ]
  [ bitwise reg 1 = ( reg 1 | reg 2 ) ]
  [ meta load mark => reg 3 ]   <--- this could use register 2 instead!
  [ bitwise reg 1 = ( reg 1 | reg 3 ) ]
  [ meta set mark with reg 1 ]

register 3 is used to store meta mark, however, register 2 can be
already use since register 1 already stores the partial result of the
bitwise operation for this expression.

After this fix:

  [ payload load 1b @ network header + 1 => reg 1 ]
  [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
  [ bitwise reg 1 = ( reg 1 >> 0x00000002 ) ]
  [ bitwise reg 1 = ( reg 1 & 0x00000003 ) ^ 0x00000000 ]
  [ ct load mark => reg 2 ]
  [ bitwise reg 1 = ( reg 1 | reg 2 ) ]
  [ meta load mark => reg 2 ]            <--- recycle register 2
  [ bitwise reg 1 = ( reg 1 | reg 2 ) ]
  [ meta set mark with reg 1 ]

Release source register in bitwise operation given destination register
already stores the partial result of the expression.

Extend tests/py to cover this.

Fixes: 54bfc38c522b ("src: allow binop expressions with variable right-hand operands")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
src/netlink_linearize.c
tests/py/any/meta.t
tests/py/any/meta.t.json
tests/py/any/meta.t.payload

index e69d323cdeaf89375eed413061b2e5a68c8e5c83..598ddfab5827bc7baf5e1e570fd1b328cb23c73c 100644 (file)
@@ -778,6 +778,7 @@ static void netlink_gen_bitwise_bool(struct netlink_linearize_ctx *ctx,
        sreg2 = get_register(ctx, expr->right);
        netlink_gen_expr(ctx, expr->right, sreg2);
        netlink_put_register(nle, NFTNL_EXPR_BITWISE_SREG2, sreg2);
+       release_register(ctx, expr->right);
 
        len = div_round_up(expr->len, BITS_PER_BYTE);
        nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_LEN, len);
index bd10c56dfe5f60ff5cb7453ffdf1a75372430c9e..3f0ef121a8c03d7623bc7bb1e97654bb04093e30 100644 (file)
@@ -228,3 +228,5 @@ meta day 7 drop;fail
 meta mark set vlan id map { 1 : 0x00000001, 4095 : 0x00004095 };ok
 !map1 typeof vlan id : meta mark;ok
 meta mark set vlan id map @map1;ok
+
+meta mark set meta mark | iif | meta cpu;ok
index 676affea4dc652c2982db72edca1474d4950aef9..65590388bb80d3967a6c31ee1b6b685fcd589c52 100644 (file)
     }
 ]
 
+# meta mark set meta mark | iif | meta cpu
+[
+    {
+        "mangle": {
+            "key": {
+                "meta": {
+                    "key": "mark"
+                }
+            },
+            "value": {
+                "|": [
+                    {
+                        "meta": {
+                            "key": "mark"
+                        }
+                    },
+                    {
+                        "meta": {
+                            "key": "iif"
+                        }
+                    },
+                    {
+                        "meta": {
+                            "key": "cpu"
+                        }
+                    }
+                ]
+            }
+        }
+    }
+]
+
index a037e0673fec7cf95d1ce3ab8ed7c49837b03da7..52c3efa84eb5d03950026b02c1d904a149ef870d 100644 (file)
@@ -1090,3 +1090,12 @@ ip test-ip4 input
   [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
   [ lookup reg 1 set map1 dreg 1 ]
   [ meta set mark with reg 1 ]
+
+# meta mark set meta mark | iif | meta cpu
+ip test-ip4 input
+  [ meta load mark => reg 1 ]
+  [ meta load iif => reg 2 ]
+  [ bitwise reg 1 = ( reg 1 | reg 2 ) ]
+  [ meta load cpu => reg 2 ]
+  [ bitwise reg 1 = ( reg 1 | reg 2 ) ]
+  [ meta set mark with reg 1 ]