To consistently print reg->val fields on different architectures, length of data in each field is relevant, because nftables simply casts u32 fields to the desired size value. Prepare nftnl_data_reg_value_snprintf_default() to accept a u8 array holding each rev->val field's size. This is compatible to data in struct nftnl_set's 'desc' field. Introduce print_data() which prints the relevant bytes of a given reg->val field depending on data and host byte order, skipping leading zeroes while doing so. Signed-off-by: Phil Sutter <phil@xxxxxx> --- src/expr/data_reg.c | 61 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 10 deletions(-) diff --git a/src/expr/data_reg.c b/src/expr/data_reg.c index 289443b47f9d6..6cbf0c4860cda 100644 --- a/src/expr/data_reg.c +++ b/src/expr/data_reg.c @@ -24,24 +24,64 @@ #include <libnftnl/rule.h> #include "internal.h" +/* return true if running on Big Endian */ +static bool host_is_be(void) +{ + const unsigned int i = 1; + + return !*(uint8_t *)&i; +} + +static int +print_data(char *buf, size_t size, uint8_t *data, size_t len, bool nbo) +{ + int ret, offset = 0, j, start = 0, end = len, inc = 1; + + /* on Little Endian with data in host byte order, reverse direction */ + if (!nbo && !host_is_be()) { + start = len - 1; + end = -1; + inc = -1; + } + + /* skip over leading nul bytes */ + for (j = start; j != end - inc && !data[j]; j += inc) + ; + + /* print all remaining bytes with leading zero */ + for (; j != end; j += inc) { + ret = snprintf(buf + offset, size, "%.2x", data[j]); + SNPRINTF_BUFFER_SIZE(ret, size, offset); + } + return offset; +} + static int nftnl_data_reg_value_snprintf_default(char *buf, size_t remain, const union nftnl_data_reg *reg, - uint32_t flags, uint16_t byteorder_bits) + uint32_t flags, uint16_t byteorder_bits, + const uint8_t *lengths) { - const char *pfx = flags & DATA_F_NOPFX ? "" : "0x"; + uint8_t lengths_fallback = reg->len; + const uint8_t *lenp = lengths; int offset = 0, ret, i; - uint32_t value; + if (!lengths || !lengths[0]) + lenp = &lengths_fallback; + for (i = 0; i * 4 < reg->len; i += div_round_up(*lenp++, 4)) { - for (i = 0; i < div_round_up(reg->len, sizeof(uint32_t)); i++) { - if (byteorder_bits & (1 << i)) - value = ntohl(reg->val[i]); - else - value = reg->val[i]; + if (!(flags & DATA_F_NOPFX)) { + ret = snprintf(buf + offset, remain, "0x"); + SNPRINTF_BUFFER_SIZE(ret, remain, offset); + } + + ret = print_data(buf + offset, remain, + (uint8_t *)(reg->val + i), + *lenp, byteorder_bits & (1 << i)); + SNPRINTF_BUFFER_SIZE(ret, remain, offset); - ret = snprintf(buf + offset, remain, "%s%.8x ", pfx, value); + ret = snprintf(buf + offset, remain, " "); SNPRINTF_BUFFER_SIZE(ret, remain, offset); } @@ -77,7 +117,8 @@ int nftnl_data_reg_snprintf(char *buf, size_t size, case DATA_VALUE: return nftnl_data_reg_value_snprintf_default(buf, size, reg, flags, - byteorder_bits); + byteorder_bits, + NULL); case DATA_VERDICT: case DATA_CHAIN: return nftnl_data_reg_verdict_snprintf_def(buf, size, -- 2.33.0