set: fix byte order metadata for host-endian types and map data#355
set: fix byte order metadata for host-endian types and map data#355anthonyrisinger wants to merge 1 commit intogoogle:mainfrom
Conversation
|
Company decided they wanted the PR from here—apologies for the noise from the last two closed!—I couldn't figure out how to open #353 again; it was the same exact commit on all three. |
There was a problem hiding this comment.
I took a look through this and left some suggestions / personal preferences. @stapelberg I don't mean to step on your toes. Just thought those comments might be helpful.
4c01b2f to
9f528f2
Compare
Fix two userdata metadata issues so byte-order information round-trips
correctly through set serialization and deserialization.
1. Parse missing set-level byte-order userdata on read:
- NFTNL_UDATA_SET_KEYBYTEORDER
- NFTNL_UDATA_SET_DATABYTEORDER
This mirrors what AddSet emits and ensures callers retrieving sets
get the same key/data byte-order metadata back.
2. Improve byte-order test coverage with a simpler round-trip approach:
- Add TestSetByteOrderRoundTrip in set_test.go.
- Cover constant/anonymous/interval sets and map cases with explicit
host/big-endian combinations for key/data.
- Verify both set metadata decoding (setsFromMsg) and element
decoding (elementsFromMsg).
This keeps behavior aligned with nft/libnftnl expectations for
KEYBYTEORDER and DATABYTEORDER handling while making tests easier to
reason about and maintain.
9f528f2 to
67d59ef
Compare
|
Let me know if there's any other changes—I simplify tests with a round-trip through both encode/decode paths. |
| } | ||
| } | ||
|
|
||
| func TestSetByteOrderRoundTrip(t *testing.T) { |
There was a problem hiding this comment.
I’m wondering whether this should remain a unit test, as it is now, or be moved to an integration test in nftables_test.go.
Running it without a test dial might give us a clearer picture of how the kernel actually responds to these parameters.
Here’s an example of what an integration test looks like:
https://github.com/google/nftables/blob/main/nftables_test.go#L8495
Fix two issues with set/map userdata byte order metadata that cause
nft list rulesetto misinterpret element keys and data values on little-endian systems. The kernel-level data is always correct — these are display/round-trip issues affecting the userdata TLVs that thenftCLI uses to reconstruct human-readable output.Bug 1: Anonymous sets ignore explicit
KeyByteOrderAnonymous/constant/interval sets unconditionally emit
KEYBYTEORDER=2(big-endian), ignoring theKeyByteOrderfield. ThenftC tool always uses the key expression's actual byte order (mnl.c:mnl_nft_set_add), not a blanket default.For host-endian types like
mark_type(BYTEORDER_HOST_ENDIAN) andifname_type(BYTEORDER_HOST_ENDIAN), this causesnft list rulesetto misinterpret the element data on LE systems:meta mark { 0x00000000, 0x01000000 }instead of{ 0x00000000, 0x00000001 }iifname vmap { "" : jump chain1 }instead of{ "eth0" : jump chain1 }The existing comment "Semantically useless - kept for binary compatability with nft" is incorrect —
KEYBYTEORDERIS semantically meaningful for host-endian types. ThenftC tool uses it innetlink_delinearize_setelemto decide whether to callmpz_switch_byteorderon element keys.Fix: When the anonymous/constant/interval condition fires, check if
KeyByteOrderis explicitly set toNativeEndianand emit1(host) instead of2(big). Falls back to the original big-endian default whenKeyByteOrderis unset (zero value), preserving backwards compatibility.Bug 2: Maps never emit
DATABYTEORDERThe
NFTNL_UDATA_SET_DATABYTEORDERconstant exists inuserdata.gobut is never used. TheSetstruct has noDataByteOrderfield, and the userdata construction has no code path that emits this TLV.The
nftC tool emitsDATABYTEORDERfor all datamaps:Without it,
nft list rulesetusesBYTEORDER_INVALIDfor map data, skips thempz_switch_byteordercall, and displays native-endian values as byte-swapped on LE systems:Fix: Add
DataByteOrderfield toSetstruct and emitNFTNL_UDATA_SET_DATABYTEORDERin the userdata construction for maps when set.Discovery context
Found while debugging a WireGuard mesh overlay that uses
meta marksets and maps for zone-based connection latching. The incorrect display made it extremely difficult to diagnose whether mark values were being set correctly, sincenft list rulesetshowed byte-swapped values but the kernel data was actually correct (verified vianft --debug=netlink list ruleset).Testing
Verified on linux/arm64 (little-endian) that after this patch:
TypeMarksets display correct values (0x00000001not0x01000000)TypeMarkdisplays correct valuesnft --debug=netlink list rulesetshows identical kernel-level bytes before and after (no functional change)GOOS=linux go build .andGOOS=linux go vet .pass cleanly