[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <5f1edf29-f83b-4dd5-b163-05d5e146bd50@redhat.com>
Date: Mon, 10 Nov 2025 14:17:06 +0100
From: Petr Oros <poros@...hat.com>
To: Stephen Hemminger <stephen@...workplumber.org>
Cc: netdev@...r.kernel.org, dsahern@...nel.org, jiri@...nulli.us,
Ivan Vecera <ivecera@...hat.com>
Subject: Re: [PATCH iproute2-next v2] dpll: Add dpll command
On 11/9/25 19:57, Stephen Hemminger wrote:
> On Fri, 7 Nov 2025 18:31:16 +0100
> Petr Oros <poros@...hat.com> wrote:
>
>> +
>> +/* Macros for printing netlink attributes
>> + * These macros combine the common pattern of:
>> + *
>> + * if (tb[ATTR])
>> + * print_xxx(PRINT_ANY, "name", "format", mnl_attr_get_xxx(tb[ATTR]));
>> + *
>> + * Generic versions with custom format string (_FMT suffix)
>> + * Simple versions auto-generate format string: " name: %d\n"
>> + */
>> +
>> +#define DPLL_PR_INT_FMT(tb, attr_id, name, format_str) \
>> + do { \
>> + if (tb[attr_id]) \
>> + print_int(PRINT_ANY, name, format_str, \
>> + mnl_attr_get_u32(tb[attr_id])); \
>> + } while (0)
>> +
>> +#define DPLL_PR_UINT_FMT(tb, attr_id, name, format_str) \
>> + do { \
>> + if (tb[attr_id]) \
>> + print_uint(PRINT_ANY, name, format_str, \
>> + mnl_attr_get_u32(tb[attr_id])); \
>> + } while (0)
>> +
>> +#define DPLL_PR_U64_FMT(tb, attr_id, name, format_str) \
>> + do { \
>> + if (tb[attr_id]) \
>> + print_lluint(PRINT_ANY, name, format_str, \
>> + mnl_attr_get_u64(tb[attr_id])); \
>> + } while (0)
>> +
>> +#define DPLL_PR_STR_FMT(tb, attr_id, name, format_str) \
>> + do { \
>> + if (tb[attr_id]) \
>> + print_string(PRINT_ANY, name, format_str, \
>> + mnl_attr_get_str(tb[attr_id])); \
>> + } while (0)
>> +
>> +/* Simple versions with auto-generated format */
>> +#define DPLL_PR_INT(tb, attr_id, name) \
>> + DPLL_PR_INT_FMT(tb, attr_id, name, " " name ": %d\n")
>> +
>> +#define DPLL_PR_UINT(tb, attr_id, name) \
>> + DPLL_PR_UINT_FMT(tb, attr_id, name, " " name ": %u\n")
>> +
>> +#define DPLL_PR_U64(tb, attr_id, name) \
>> + DPLL_PR_U64_FMT(tb, attr_id, name, " " name ": %" PRIu64 "\n")
>> +
>> +/* Helper to read signed int (can be s32 or s64 depending on value) */
>> +static __s64 mnl_attr_get_sint(const struct nlattr *attr)
>> +{
>> + if (mnl_attr_get_payload_len(attr) == sizeof(__s32))
>> + return *(__s32 *)mnl_attr_get_payload(attr);
>> + else
>> + return *(__s64 *)mnl_attr_get_payload(attr);
>> +}
>> +
>> +#define DPLL_PR_SINT_FMT(tb, attr_id, name, format_str) \
>> + do { \
>> + if (tb[attr_id]) \
>> + print_s64(PRINT_ANY, name, format_str, \
>> + mnl_attr_get_sint(tb[attr_id])); \
>> + } while (0)
>> +
>> +#define DPLL_PR_SINT(tb, attr_id, name) \
>> + DPLL_PR_SINT_FMT(tb, attr_id, name, " " name ": %" PRId64 "\n")
>> +
>> +#define DPLL_PR_STR(tb, attr_id, name) \
>> + DPLL_PR_STR_FMT(tb, attr_id, name, " " name ": %s\n")
>> +
>> +/* Temperature macro - JSON prints raw millidegrees, human prints formatted */
>> +#define DPLL_PR_TEMP(tb, attr_id) \
>> + do { \
>> + if (tb[attr_id]) { \
>> + __s32 temp = mnl_attr_get_u32(tb[attr_id]); \
>> + if (is_json_context()) { \
>> + print_int(PRINT_JSON, "temp", NULL, temp); \
>> + } else { \
>> + div_t d = div(temp, 1000); \
>> + pr_out(" temp: %d.%03d C\n", d.quot, d.rem); \
>> + } \
>> + } \
>> + } while (0)
>> +
>> +/* Generic version with custom format */
>> +#define DPLL_PR_ENUM_STR_FMT(tb, attr_id, name, format_str, name_func) \
>> + do { \
>> + if (tb[attr_id]) \
>> + print_string( \
>> + PRINT_ANY, name, format_str, \
>> + name_func(mnl_attr_get_u32(tb[attr_id]))); \
>> + } while (0)
>> +
>> +/* Simple version with auto-generated format */
>> +#define DPLL_PR_ENUM_STR(tb, attr_id, name, name_func) \
>> + DPLL_PR_ENUM_STR_FMT(tb, attr_id, name, " " name ": %s\n", name_func)
>> +
>> +/* Multi-attr enum printer - handles multiple occurrences of same attribute */
>> +#define DPLL_PR_MULTI_ENUM_STR(nlh, attr_id, name, name_func) \
>> + do { \
>> + struct nlattr *__attr; \
>> + bool __first = true; \
>> + \
>> + if (!nlh) \
>> + break; \
>> + \
>> + mnl_attr_for_each(__attr, nlh, sizeof(struct genlmsghdr)) \
>> + { \
>> + if (mnl_attr_get_type(__attr) == (attr_id)) { \
>> + __u32 __val = mnl_attr_get_u32(__attr); \
>> + if (__first) { \
>> + if (is_json_context()) { \
>> + open_json_array(PRINT_JSON, \
>> + name); \
>> + } else { \
>> + pr_out(" " name ":"); \
>> + } \
>> + __first = false; \
>> + } \
>> + if (is_json_context()) { \
>> + print_string(PRINT_JSON, NULL, NULL, \
>> + name_func(__val)); \
>> + } else { \
>> + pr_out(" %s", name_func(__val)); \
>> + } \
>> + } \
>> + } \
>> + if (__first) \
>> + break; \
>> + if (is_json_context()) { \
>> + close_json_array(PRINT_JSON, NULL); \
>> + } else { \
>> + pr_out("\n"); \
>> + } \
>> + } while (0)
>> +
> Code with large macros is harder to read and harder to maintain.
> Why can this not be inline functions?
> Why do you need to reinvent yet another netlink parser.
>
> Code that does is_json_context() is more verbose than necessary.
I understand the concern about the large macro. I used it mainly for
consistency with the existing DPLL_PR_* helpers, and it did not feel
excessively large in that context.
What I do not fully understand is the comment “Why do you need to
reinvent yet another netlink parser?”. The macros are only meant to
simplify the repeated pattern:
if (tb[ATTR]) print_xxx(PRINT_ANY, "name", "format",
mnl_attr_get_xxx(tb[ATTR]));
Is the issue that you would prefer to drop these macros entirely and use
this pattern
directly everywhere, or did you mean something else?
>
>> + if (is_json_context()) { \
>> + print_string(PRINT_JSON, NULL, NULL, \
>> + name_func(__val)); \
>> + } else { \
>> + pr_out(" %s", name_func(__val)); \
>> + }
> Can be replaced by:
> print_string(PRINT_ANY, NULL, " %s", name_func(__val));
ok, i will fix it in v3
>
> Please use existing code patterns.
>
Powered by blists - more mailing lists