set s { typeof tcp option mptcp subtype elements = { mp-join, dss } } is listed correctly. The set key provides the 'mptcpopt_subtype' information and listing can print all elements with symbolic names. In anon set case this doesn't work: tcp option mptcp subtype { mp-join, dss } is printed as "... subtype { 1, 2}" because the anon set only provides plain integer type. This change propagates the datatype to the individual members of the anon set. After this change, multiple existing data types such as TYPE_ICMP_TYPE could theoretically be replaced by integer-type aliases. However, those datatypes are already exposed to userspace via the 'set type' keyword. Thus removing them will break set definitions that use them. Signed-off-by: Florian Westphal <fw@xxxxxxxxx> --- src/expression.c | 35 +++++++++++++++++++++++++++++++++++ tests/py/any/tcpopt.t | 2 +- tests/py/any/tcpopt.t.json | 11 ++++++++--- tests/py/any/tcpopt.t.payload | 10 +++++----- 4 files changed, 49 insertions(+), 9 deletions(-) diff --git a/src/expression.c b/src/expression.c index 53d4c521ae18..d2fa46509262 100644 --- a/src/expression.c +++ b/src/expression.c @@ -1485,6 +1485,32 @@ static void set_ref_expr_destroy(struct expr *expr) set_free(expr->set); } +static void set_ref_expr_set_type(const struct expr *expr, + const struct datatype *dtype, + enum byteorder byteorder) +{ + const struct set *s = expr->set; + + /* normal sets already have a precise datatype that is given in + * the set definition via type foo. + * + * Anon sets do not have this, and need to rely on type info + * generated at rule creation time. + * + * For most cases, the type info is correct. + * In some cases however, the kernel only stores TYPE_INTEGER. + * + * This happens with expressions that only use an integer alias + * type, e.g. the mptcpopt_subtype datatype. + * + * In this case nft will print the elements as numerical values + * because the base type lacks the ->sym_tbl information of the + * subtypes. + */ + if (s->init && set_is_anonymous(s->flags)) + expr_set_type(s->init, dtype, byteorder); +} + static const struct expr_ops set_ref_expr_ops = { .type = EXPR_SET_REF, .name = "set reference", @@ -1492,6 +1518,7 @@ static const struct expr_ops set_ref_expr_ops = { .json = set_ref_expr_json, .clone = set_ref_expr_clone, .destroy = set_ref_expr_destroy, + .set_type = set_ref_expr_set_type, }; struct expr *set_ref_expr_alloc(const struct location *loc, struct set *set) @@ -1556,6 +1583,13 @@ static void set_elem_expr_clone(struct expr *new, const struct expr *expr) __set_elem_expr_clone(new, expr); } +static void set_elem_expr_set_type(const struct expr *expr, + const struct datatype *dtype, + enum byteorder byteorder) +{ + expr_set_type(expr->key, dtype, byteorder); +} + static const struct expr_ops set_elem_expr_ops = { .type = EXPR_SET_ELEM, .name = "set element", @@ -1563,6 +1597,7 @@ static const struct expr_ops set_elem_expr_ops = { .print = set_elem_expr_print, .json = set_elem_expr_json, .destroy = set_elem_expr_destroy, + .set_type = set_elem_expr_set_type, }; struct expr *set_elem_expr_alloc(const struct location *loc, struct expr *key) diff --git a/tests/py/any/tcpopt.t b/tests/py/any/tcpopt.t index a2fcdb3afb25..79699e23a4b1 100644 --- a/tests/py/any/tcpopt.t +++ b/tests/py/any/tcpopt.t @@ -53,7 +53,7 @@ tcp option mptcp exists;ok tcp option mptcp subtype mp-capable;ok tcp option mptcp subtype 1;ok;tcp option mptcp subtype mp-join -tcp option mptcp subtype { 0, 2};ok +tcp option mptcp subtype { mp-capable, mp-join, remove-addr, mp-prio, mp-fail, mp-fastclose, mp-tcprst };ok reset tcp option mptcp;ok reset tcp option 2;ok;reset tcp option maxseg diff --git a/tests/py/any/tcpopt.t.json b/tests/py/any/tcpopt.t.json index ea580473c8ad..a02e71b66c36 100644 --- a/tests/py/any/tcpopt.t.json +++ b/tests/py/any/tcpopt.t.json @@ -565,7 +565,7 @@ } ] -# tcp option mptcp subtype { 0, 2} +# tcp option mptcp subtype { mp-capable, mp-join, remove-addr, mp-prio, mp-fail, mp-fastclose, mp-tcprst } [ { "match": { @@ -578,8 +578,13 @@ "op": "==", "right": { "set": [ - 0, - 2 + "mp-capable", + "mp-join", + "remove-addr", + "mp-prio", + "mp-fail", + "mp-fastclose", + "mp-tcprst" ] } } diff --git a/tests/py/any/tcpopt.t.payload b/tests/py/any/tcpopt.t.payload index e3cf500b964b..af8c4317e567 100644 --- a/tests/py/any/tcpopt.t.payload +++ b/tests/py/any/tcpopt.t.payload @@ -180,11 +180,11 @@ inet [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ] [ cmp eq reg 1 0x00000010 ] -# tcp option mptcp subtype { 0, 2} -__set%d test-inet 3 size 2 -__set%d test-inet 0 - element 00000000 : 0 [end] element 00000020 : 0 [end] -inet +# tcp option mptcp subtype { mp-capable, mp-join, remove-addr, mp-prio, mp-fail, mp-fastclose, mp-tcprst } +__set%d test-ip4 3 size 7 +__set%d test-ip4 0 + element 00000000 : 0 [end] element 00000010 : 0 [end] element 00000040 : 0 [end] element 00000050 : 0 [end] element 00000060 : 0 [end] element 00000070 : 0 [end] element 00000080 : 0 [end] +ip test-ip4 input [ exthdr load tcpopt 1b @ 30 + 2 => reg 1 ] [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ] [ lookup reg 1 set __set%d ] -- 2.45.3