]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
src: allow anon set concatenation with ether and vlan
authorFlorian Westphal <fw@strlen.de>
Mon, 25 Jul 2022 19:34:52 +0000 (21:34 +0200)
committerFlorian Westphal <fw@strlen.de>
Thu, 4 Aug 2022 23:46:39 +0000 (01:46 +0200)
vlan id uses integer type (which has a length of 0).

Using it was possible, but listing would assert:
python: mergesort.c:24: concat_expr_msort_value: Assertion `ilen > 0' failed.

There are two reasons for this.
First reason is that the udata/typeof information lacks the 'vlan id'
part, because internally this is 'payload . binop(payload AND mask)'.

binop lacks an udata store.  It makes little sense to store it,
'typeof' keyword expects normal match syntax.

So, when storing udata, store the left hand side of the binary
operation, i.e. the load of the 2-byte key.

With that resolved, delinerization could work, but concat_elem_expr()
would splice 12 bits off the elements value, but it should be 16 (on
a byte boundary).

Signed-off-by: Florian Westphal <fw@strlen.de>
src/expression.c
src/netlink.c
tests/py/bridge/vlan.t
tests/py/bridge/vlan.t.json
tests/py/bridge/vlan.t.payload
tests/py/bridge/vlan.t.payload.netdev

index deb649e1847bb935735cf0a681c5a2c1fb663c0e..7390089cf57d07a545977f48cb9d3e219d22e8cd 100644 (file)
@@ -879,17 +879,30 @@ static void concat_expr_print(const struct expr *expr, struct output_ctx *octx)
 #define NFTNL_UDATA_SET_KEY_CONCAT_SUB_DATA 1
 #define NFTNL_UDATA_SET_KEY_CONCAT_SUB_MAX  2
 
+static struct expr *expr_build_udata_recurse(struct expr *e)
+{
+       switch (e->etype) {
+       case EXPR_BINOP:
+               return e->left;
+       default:
+               break;
+       }
+
+       return e;
+}
+
 static int concat_expr_build_udata(struct nftnl_udata_buf *udbuf,
                                    const struct expr *concat_expr)
 {
        struct nftnl_udata *nest;
+       struct expr *expr, *tmp;
        unsigned int i = 0;
-       struct expr *expr;
 
-       list_for_each_entry(expr, &concat_expr->expressions, list) {
+       list_for_each_entry_safe(expr, tmp, &concat_expr->expressions, list) {
                struct nftnl_udata *nest_expr;
                int err;
 
+               expr = expr_build_udata_recurse(expr);
                if (!expr_ops(expr)->build_udata || i >= NFT_REG32_SIZE)
                        return -1;
 
index 89d864ed046aa2abf8800ade6980f64e19ec7e88..799cf9b8ebefb08095dee742a18ef34d90012b68 100644 (file)
@@ -1114,17 +1114,21 @@ static struct expr *concat_elem_expr(struct expr *key,
                                     struct expr *data, int *off)
 {
        const struct datatype *subtype;
+       unsigned int sub_length;
        struct expr *expr;
 
        if (key) {
                (*off)--;
-               expr = constant_expr_splice(data, key->len);
+               sub_length = round_up(key->len, BITS_PER_BYTE);
+
+               expr = constant_expr_splice(data, sub_length);
                expr->dtype = datatype_get(key->dtype);
                expr->byteorder = key->byteorder;
                expr->len = key->len;
        } else {
                subtype = concat_subtype_lookup(dtype->type, --(*off));
-               expr = constant_expr_splice(data, subtype->size);
+               sub_length = round_up(subtype->size, BITS_PER_BYTE);
+               expr = constant_expr_splice(data, sub_length);
                expr->dtype = subtype;
                expr->byteorder = subtype->byteorder;
        }
@@ -1136,7 +1140,7 @@ static struct expr *concat_elem_expr(struct expr *key,
            expr->dtype->basetype->type == TYPE_BITMASK)
                expr = bitmask_expr_to_binops(expr);
 
-       data->len -= netlink_padding_len(expr->len);
+       data->len -= netlink_padding_len(sub_length);
 
        return expr;
 }
index 49206017fff283896cb3d73c39189edcc5791e6d..95bdff4f1b7534c8db1879246b79fab5fc3f4d84 100644 (file)
@@ -50,3 +50,5 @@ vlan id 1 vlan id set 2;ok
 
 ether saddr 00:01:02:03:04:05 vlan id 1;ok
 vlan id 2 ether saddr 0:1:2:3:4:6;ok;ether saddr 00:01:02:03:04:06 vlan id 2
+
+ether saddr . vlan id { 0a:0b:0c:0d:0e:0f . 42, 0a:0b:0c:0d:0e:0f . 4095 };ok
index 58d4a40f5bafc57df1b72fe029900b639505672d..f77756f5080a6269a066e88d53a705d4c89e3bc6 100644 (file)
         }
     }
 ]
+
+# ether saddr . vlan id { 0a:0b:0c:0d:0e:0f . 42, 0a:0b:0c:0d:0e:0f . 4095 }
+[
+    {
+        "match": {
+            "left": {
+                "concat": [
+                    {
+                        "payload": {
+                            "field": "saddr",
+                            "protocol": "ether"
+                        }
+                    },
+                    {
+                        "payload": {
+                            "field": "id",
+                            "protocol": "vlan"
+                        }
+                    }
+                ]
+            },
+            "op": "==",
+            "right": {
+                "set": [
+                    {
+                        "concat": [
+                            "0a:0b:0c:0d:0e:0f",
+                            42
+                        ]
+                    },
+                    {
+                        "concat": [
+                            "0a:0b:0c:0d:0e:0f",
+                            4095
+                        ]
+                    }
+                ]
+            }
+        }
+    }
+]
index 713670e9e721ecf1235d967878946953cb2a0971..62e4b89bd0b25bdb55eeccbc48ccf9dd32b00ade 100644 (file)
@@ -292,3 +292,15 @@ bridge test-bridge input
   [ payload load 2b @ link header + 14 => reg 1 ]
   [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
   [ cmp eq reg 1 0x00000200 ]
+
+# ether saddr . vlan id { 0a:0b:0c:0d:0e:0f . 42, 0a:0b:0c:0d:0e:0f . 4095 }
+__set%d test-bridge 3 size 2
+__set%d test-bridge 0
+       element 0d0c0b0a 00000f0e 00002a00  : 0 [end]   element 0d0c0b0a 00000f0e 0000ff0f  : 0 [end]
+bridge test-bridge input
+  [ payload load 2b @ link header + 12 => reg 1 ]
+  [ cmp eq reg 1 0x00000081 ]
+  [ payload load 6b @ link header + 6 => reg 1 ]
+  [ payload load 2b @ link header + 14 => reg 10 ]
+  [ bitwise reg 10 = ( reg 10 & 0x0000ff0f ) ^ 0x00000000 ]
+  [ lookup reg 1 set __set%d ]
index 98a2a2b0f3798c5c89b7bd1b8ab1cda1669df77f..1018d4c6588ffdae24e36821a4632b35ef2bb566 100644 (file)
@@ -342,3 +342,17 @@ netdev test-netdev ingress
   [ payload load 2b @ link header + 14 => reg 1 ]
   [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
   [ cmp eq reg 1 0x00000100 ]
+
+# ether saddr . vlan id { 0a:0b:0c:0d:0e:0f . 42, 0a:0b:0c:0d:0e:0f . 4095 }
+__set%d test-netdev 3 size 2
+__set%d test-netdev 0
+       element 0d0c0b0a 00000f0e 00002a00  : 0 [end]   element 0d0c0b0a 00000f0e 0000ff0f  : 0 [end]
+netdev test-netdev ingress
+  [ meta load iiftype => reg 1 ]
+  [ cmp eq reg 1 0x00000001 ]
+  [ payload load 2b @ link header + 12 => reg 1 ]
+  [ cmp eq reg 1 0x00000081 ]
+  [ payload load 6b @ link header + 6 => reg 1 ]
+  [ payload load 2b @ link header + 14 => reg 10 ]
+  [ bitwise reg 10 = ( reg 10 & 0x0000ff0f ) ^ 0x00000000 ]
+  [ lookup reg 1 set __set%d ]