nft can be used t match on specific multipath tcp subtypes: tcp option mptcp subtype 0 However, depending on which subtype to match, users need to look up the type/value to use in rfc8684. Add support for mnemonics and "nft describe tcp option mptcp subtype" to get the subtype list. Because the number of unique 'enum datatypes' is limited by ABI contraints this adds a new mptcp suboption type as integer alias. After this patch, nft supports all of the following: add element t s { mp-capable } add rule t c tcp option mptcp subtype mp-capable add rule t c tcp option mptcp subtype { mp-capable, mp-fail } For the 3rd case, listing will break because unlike for named sets, nft lacks the type information needed to pretty-print the integer values, i.e. nft will print the 3rd rule as 'subtype { 0, 6 }'. This is resolved in a followup patch. Other problematic constructs are: set s1 { typeof tcp option mptcp subtype . ip saddr elements = { mp-fail . 1.2.3.4 } } Followed by: tcp option mptcp subtype . ip saddr @s1 nft will print this as: tcp option mptcp unknown & 240) >> 4 . ip saddr @s1 All of these issues are not related to this patch, however, they also occur with other bit-sized extheader fields. Signed-off-by: Florian Westphal <fw@xxxxxxxxx> --- include/datatype.h | 5 +++- src/tcpopt.c | 30 ++++++++++++++++++- tests/py/any/tcpopt.t | 4 +-- tests/py/any/tcpopt.t.json | 6 ++-- tests/py/any/tcpopt.t.payload | 2 +- .../testcases/sets/dumps/typeof_sets_0.nft | 9 ++++++ tests/shell/testcases/sets/typeof_sets_0 | 18 +++++++++++ 7 files changed, 66 insertions(+), 8 deletions(-) diff --git a/include/datatype.h b/include/datatype.h index 8b950f9165a5..4fb47f158fc2 100644 --- a/include/datatype.h +++ b/include/datatype.h @@ -251,7 +251,6 @@ extern const struct datatype verdict_type; extern const struct datatype nfproto_type; extern const struct datatype bitmask_type; extern const struct datatype integer_type; -extern const struct datatype xinteger_type; extern const struct datatype string_type; extern const struct datatype lladdr_type; extern const struct datatype ipaddr_type; @@ -279,6 +278,10 @@ extern const struct datatype reject_icmp_code_type; extern const struct datatype reject_icmpv6_code_type; extern const struct datatype reject_icmpx_code_type; +/* TYPE_INTEGER aliases: */ +extern const struct datatype xinteger_type; +extern const struct datatype mptcpopt_subtype; + void inet_service_type_print(const struct expr *expr, struct output_ctx *octx); extern const struct datatype *concat_type_alloc(uint32_t type); diff --git a/src/tcpopt.c b/src/tcpopt.c index f977e417536a..d8139337cc20 100644 --- a/src/tcpopt.c +++ b/src/tcpopt.c @@ -108,6 +108,31 @@ static const struct exthdr_desc tcpopt_md5sig = { }, }; +static const struct symbol_table mptcp_subtype_tbl = { + .base = BASE_DECIMAL, + .symbols = { + SYMBOL("mp-capable", 0), + SYMBOL("mp-join", 1), + SYMBOL("dss", 2), + SYMBOL("add-addr", 3), + SYMBOL("remove-addr", 4), + SYMBOL("mp-prio", 5), + SYMBOL("mp-fail", 6), + SYMBOL("mp-fastclose", 7), + SYMBOL("mp-tcprst", 8), + SYMBOL_LIST_END + }, +}; + +/* alias of integer_type to parse mptcp subtypes */ +const struct datatype mptcpopt_subtype = { + .type = TYPE_INTEGER, + .name = "integer", + .desc = "mptcp option subtype", + .size = 4, + .basetype = &integer_type, + .sym_tbl = &mptcp_subtype_tbl, +}; static const struct exthdr_desc tcpopt_mptcp = { .name = "mptcp", @@ -115,7 +140,10 @@ static const struct exthdr_desc tcpopt_mptcp = { .templates = { [TCPOPT_MPTCP_KIND] = PHT("kind", 0, 8), [TCPOPT_MPTCP_LENGTH] = PHT("length", 8, 8), - [TCPOPT_MPTCP_SUBTYPE] = PHT("subtype", 16, 4), + [TCPOPT_MPTCP_SUBTYPE] = PROTO_HDR_TEMPLATE("subtype", + &mptcpopt_subtype, + BYTEORDER_BIG_ENDIAN, + 16, 4), }, }; diff --git a/tests/py/any/tcpopt.t b/tests/py/any/tcpopt.t index 177f01c45506..a2fcdb3afb25 100644 --- a/tests/py/any/tcpopt.t +++ b/tests/py/any/tcpopt.t @@ -51,8 +51,8 @@ tcp option md5sig exists;ok tcp option fastopen exists;ok tcp option mptcp exists;ok -tcp option mptcp subtype 0;ok -tcp option mptcp subtype 1;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 reset tcp option mptcp;ok diff --git a/tests/py/any/tcpopt.t.json b/tests/py/any/tcpopt.t.json index 87074b9d216a..ea580473c8ad 100644 --- a/tests/py/any/tcpopt.t.json +++ b/tests/py/any/tcpopt.t.json @@ -533,7 +533,7 @@ } ] -# tcp option mptcp subtype 0 +# tcp option mptcp subtype mp-capable [ { "match": { @@ -544,7 +544,7 @@ } }, "op": "==", - "right": 0 + "right": "mp-capable" } } ] @@ -560,7 +560,7 @@ } }, "op": "==", - "right": 1 + "right": "mp-join" } } ] diff --git a/tests/py/any/tcpopt.t.payload b/tests/py/any/tcpopt.t.payload index 99b8985f0f68..e3cf500b964b 100644 --- a/tests/py/any/tcpopt.t.payload +++ b/tests/py/any/tcpopt.t.payload @@ -168,7 +168,7 @@ inet [ exthdr load tcpopt 1b @ 30 + 0 present => reg 1 ] [ cmp eq reg 1 0x00000001 ] -# tcp option mptcp subtype 0 +# tcp option mptcp subtype mp-capable inet [ exthdr load tcpopt 1b @ 30 + 2 => reg 1 ] [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ] diff --git a/tests/shell/testcases/sets/dumps/typeof_sets_0.nft b/tests/shell/testcases/sets/dumps/typeof_sets_0.nft index 63fc5b145137..ed45d84a0eff 100644 --- a/tests/shell/testcases/sets/dumps/typeof_sets_0.nft +++ b/tests/shell/testcases/sets/dumps/typeof_sets_0.nft @@ -60,6 +60,11 @@ table inet t { elements = { "eth0" . 10.1.1.2 . exists } } + set s13 { + typeof tcp option mptcp subtype + elements = { mp-join, dss } + } + chain c1 { osf name @s1 accept } @@ -103,4 +108,8 @@ table inet t { chain c12 { iifname . ip saddr . meta ipsec @s12 accept } + + chain c13 { + tcp option mptcp subtype @s13 accept + } } diff --git a/tests/shell/testcases/sets/typeof_sets_0 b/tests/shell/testcases/sets/typeof_sets_0 index a105acffde48..5ba7fc76ce15 100755 --- a/tests/shell/testcases/sets/typeof_sets_0 +++ b/tests/shell/testcases/sets/typeof_sets_0 @@ -119,6 +119,11 @@ INPUT="table inet t {$INPUT_OSF_SET typeof meta iifname . ip saddr . meta ipsec elements = { \"eth0\" . 10.1.1.2 . 1 } } + + set s13 { + typeof tcp option mptcp subtype + elements = { mp-join, dss } + } $INPUT_OSF_CHAIN chain c2 { ether type vlan vlan id @s2 accept @@ -148,6 +153,10 @@ $INPUT_VERSION_CHAIN chain c12 { meta iifname . ip saddr . meta ipsec @s12 accept } + + chain c13 { + tcp option mptcp subtype @s13 accept + } }" EXPECTED="table inet t {$INPUT_OSF_SET @@ -196,6 +205,11 @@ $INPUT_VERSION_SET typeof iifname . ip saddr . meta ipsec elements = { \"eth0\" . 10.1.1.2 . exists } } + + set s13 { + typeof tcp option mptcp subtype + elements = { mp-join, dss } + } $INPUT_OSF_CHAIN chain c2 { vlan id @s2 accept @@ -224,6 +238,10 @@ $INPUT_SCTP_CHAIN$INPUT_VERSION_CHAIN chain c12 { iifname . ip saddr . meta ipsec @s12 accept } + + chain c13 { + tcp option mptcp subtype @s13 accept + } }" -- 2.45.3