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 use 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@xxxxxxxxxxxxx> --- src/netlink_linearize.c | 1 + tests/py/any/meta.t | 2 ++ tests/py/any/meta.t.json | 32 ++++++++++++++++++++++++++++++++ tests/py/any/meta.t.payload | 9 +++++++++ 4 files changed, 44 insertions(+) diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c index e69d323cdeaf..598ddfab5827 100644 --- a/src/netlink_linearize.c +++ b/src/netlink_linearize.c @@ -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); diff --git a/tests/py/any/meta.t b/tests/py/any/meta.t index bd10c56dfe5f..3f0ef121a8c0 100644 --- a/tests/py/any/meta.t +++ b/tests/py/any/meta.t @@ -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 diff --git a/tests/py/any/meta.t.json b/tests/py/any/meta.t.json index 676affea4dc6..65590388bb80 100644 --- a/tests/py/any/meta.t.json +++ b/tests/py/any/meta.t.json @@ -2818,3 +2818,35 @@ } ] +# meta mark set meta mark | iif | meta cpu +[ + { + "mangle": { + "key": { + "meta": { + "key": "mark" + } + }, + "value": { + "|": [ + { + "meta": { + "key": "mark" + } + }, + { + "meta": { + "key": "iif" + } + }, + { + "meta": { + "key": "cpu" + } + } + ] + } + } + } +] + diff --git a/tests/py/any/meta.t.payload b/tests/py/any/meta.t.payload index a037e0673fec..52c3efa84eb5 100644 --- a/tests/py/any/meta.t.payload +++ b/tests/py/any/meta.t.payload @@ -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 ] -- 2.30.2