diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-08-26 10:34:19 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-08-26 10:34:19 +0000 |
commit | 942dc614706293cdedc7dede7dc09d8fdf9583f2 (patch) | |
tree | 39a8bf3ebede54ce9aea189de4036398199ee6e9 /netlink | |
parent | Adding upstream version 1:6.9. (diff) | |
download | ethtool-upstream/1%6.10.tar.xz ethtool-upstream/1%6.10.zip |
Adding upstream version 1:6.10.upstream/1%6.10upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'netlink')
-rw-r--r-- | netlink/eee.c | 41 | ||||
-rw-r--r-- | netlink/module-eeprom.c | 30 | ||||
-rw-r--r-- | netlink/netlink.h | 2 | ||||
-rw-r--r-- | netlink/parser.c | 11 | ||||
-rw-r--r-- | netlink/pse-pd.c | 66 | ||||
-rw-r--r-- | netlink/settings.c | 269 | ||||
-rw-r--r-- | netlink/tsinfo.c | 65 |
7 files changed, 354 insertions, 130 deletions
diff --git a/netlink/eee.c b/netlink/eee.c index 04d8f0b..51b9d10 100644 --- a/netlink/eee.c +++ b/netlink/eee.c @@ -14,6 +14,7 @@ #include "netlink.h" #include "bitset.h" #include "parser.h" +#include "../json_writer.h" /* EEE_GET */ @@ -21,13 +22,13 @@ int eee_reply_cb(const struct nlmsghdr *nlhdr, void *data) { const struct nlattr *tb[ETHTOOL_A_EEE_MAX + 1] = {}; DECLARE_ATTR_TB_INFO(tb); - bool enabled, active, tx_lpi_enabled; + bool enabled, active, tx_lpi_enabled, status_support; struct nl_context *nlctx = data; bool silent; int err_ret; int ret; - silent = nlctx->is_dump || nlctx->is_monitor; + silent = nlctx->is_dump || nlctx->is_monitor || is_json_context(); err_ret = silent ? MNL_CB_OK : MNL_CB_ERROR; ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info); if (ret < 0) @@ -46,42 +47,43 @@ int eee_reply_cb(const struct nlmsghdr *nlhdr, void *data) active = mnl_attr_get_u8(tb[ETHTOOL_A_EEE_ACTIVE]); enabled = mnl_attr_get_u8(tb[ETHTOOL_A_EEE_ENABLED]); tx_lpi_enabled = mnl_attr_get_u8(tb[ETHTOOL_A_EEE_TX_LPI_ENABLED]); + status_support = bitset_is_empty(tb[ETHTOOL_A_EEE_MODES_OURS], true, &ret); if (silent) putchar('\n'); - printf("EEE settings for %s:\n", nlctx->devname); - printf("\tEEE status: "); - if (bitset_is_empty(tb[ETHTOOL_A_EEE_MODES_OURS], true, &ret)) { - printf("not supported\n"); + print_string(PRINT_ANY, "ifname", "EEE settings for %s:\n", nlctx->devname); + print_string(PRINT_FP, NULL, "\tEEE status: ", NULL); + if (status_support) { + print_string(PRINT_ANY, "status", "%s\n", "not supported"); return MNL_CB_OK; } if (!enabled) - printf("disabled\n"); + print_string(PRINT_ANY, "status", "%s\n", "disabled"); else - printf("enabled - %s\n", active ? "active" : "inactive"); - printf("\tTx LPI: "); + print_string(PRINT_ANY, "status", "enabled - %s\n", active ? "active" : "inactive"); + print_string(PRINT_FP, NULL, "\tTx LPI: ", NULL); if (tx_lpi_enabled) - printf("%u (us)\n", + print_uint(PRINT_ANY, "tx-lpi", "%u (us)\n", mnl_attr_get_u32(tb[ETHTOOL_A_EEE_TX_LPI_TIMER])); else - printf("disabled\n"); + print_string(PRINT_FP, NULL, "%s\n", "disabled"); ret = dump_link_modes(nlctx, tb[ETHTOOL_A_EEE_MODES_OURS], true, LM_CLASS_REAL, "Supported EEE link modes: ", NULL, "\n", - "Not reported"); + "Not reported", "supported-eee-link-modes"); if (ret < 0) return err_ret; ret = dump_link_modes(nlctx, tb[ETHTOOL_A_EEE_MODES_OURS], false, LM_CLASS_REAL, "Advertised EEE link modes: ", NULL, "\n", - "Not reported"); + "Not reported", "advertised-eee-link-modes"); if (ret < 0) return err_ret; ret = dump_link_modes(nlctx, tb[ETHTOOL_A_EEE_MODES_PEER], false, LM_CLASS_REAL, "Link partner advertised EEE link modes: ", NULL, - "\n", "Not reported"); + "\n", "Not reported", "link-partner-advertised-eee-link-modes"); if (ret < 0) return err_ret; @@ -102,11 +104,18 @@ int nl_geee(struct cmd_context *ctx) return 1; } + new_json_obj(ctx->json); + open_json_object(NULL); + ret = nlsock_prep_get_request(nlsk, ETHTOOL_MSG_EEE_GET, ETHTOOL_A_EEE_HEADER, 0); if (ret < 0) - return ret; - return nlsock_send_get_request(nlsk, eee_reply_cb); + goto out; + ret = nlsock_send_get_request(nlsk, eee_reply_cb); +out: + close_json_object(); + delete_json_obj(); + return ret; } /* EEE_SET */ diff --git a/netlink/module-eeprom.c b/netlink/module-eeprom.c index fe02c5a..2b30d04 100644 --- a/netlink/module-eeprom.c +++ b/netlink/module-eeprom.c @@ -22,6 +22,7 @@ #define ETH_I2C_MAX_ADDRESS 0x7F struct cmd_params { + unsigned long present; u8 dump_hex; u8 dump_raw; u32 offset; @@ -31,6 +32,14 @@ struct cmd_params { u32 i2c_address; }; +enum { + PARAM_OFFSET = 2, + PARAM_LENGTH, + PARAM_PAGE, + PARAM_BANK, + PARAM_I2C, +}; + static const struct param_parser getmodule_params[] = { { .arg = "hex", @@ -44,31 +53,31 @@ static const struct param_parser getmodule_params[] = { .dest_offset = offsetof(struct cmd_params, dump_raw), .min_argc = 1, }, - { + [PARAM_OFFSET] = { .arg = "offset", .handler = nl_parse_direct_u32, .dest_offset = offsetof(struct cmd_params, offset), .min_argc = 1, }, - { + [PARAM_LENGTH] = { .arg = "length", .handler = nl_parse_direct_u32, .dest_offset = offsetof(struct cmd_params, length), .min_argc = 1, }, - { + [PARAM_PAGE] = { .arg = "page", .handler = nl_parse_direct_u32, .dest_offset = offsetof(struct cmd_params, page), .min_argc = 1, }, - { + [PARAM_BANK] = { .arg = "bank", .handler = nl_parse_direct_u32, .dest_offset = offsetof(struct cmd_params, bank), .min_argc = 1, }, - { + [PARAM_I2C] = { .arg = "i2c", .handler = nl_parse_direct_u32, .dest_offset = offsetof(struct cmd_params, i2c_address), @@ -267,15 +276,18 @@ int nl_getmodule(struct cmd_context *ctx) * ioctl. Netlink can only request specific pages. */ if ((getmodule_cmd_params.dump_hex || getmodule_cmd_params.dump_raw) && - !getmodule_cmd_params.page && !getmodule_cmd_params.bank && - !getmodule_cmd_params.i2c_address) { + !(getmodule_cmd_params.present & (1 << PARAM_PAGE | + 1 << PARAM_BANK | + 1 << PARAM_I2C))) { nlctx->ioctl_fallback = true; return -EOPNOTSUPP; } #ifdef ETHTOOL_ENABLE_PRETTY_DUMP - if (getmodule_cmd_params.page || getmodule_cmd_params.bank || - getmodule_cmd_params.offset || getmodule_cmd_params.length) + if (getmodule_cmd_params.present & (1 << PARAM_PAGE | + 1 << PARAM_BANK | + 1 << PARAM_OFFSET | + 1 << PARAM_LENGTH)) #endif getmodule_cmd_params.dump_hex = true; diff --git a/netlink/netlink.h b/netlink/netlink.h index 1274a3b..4a4b68b 100644 --- a/netlink/netlink.h +++ b/netlink/netlink.h @@ -98,7 +98,7 @@ int module_reply_cb(const struct nlmsghdr *nlhdr, void *data); int dump_link_modes(struct nl_context *nlctx, const struct nlattr *bitset, bool mask, unsigned int class, const char *before, const char *between, const char *after, - const char *if_none); + const char *if_none, const char *json_key); static inline void show_u32(const char *key, const char *fmt, diff --git a/netlink/parser.c b/netlink/parser.c index 6f86361..cd32752 100644 --- a/netlink/parser.c +++ b/netlink/parser.c @@ -996,7 +996,7 @@ static void tmp_buff_destroy(struct tmp_buff *head) * and their handlers; the array must be terminated by null * element {} * @dest: optional destination to copy parsed data to (at - * param_parser::offset) + * param_parser::offset); buffer should start with presence bitmap * @group_style: defines if identifiers in .group represent separate messages, * nested attributes or are not allowed * @msgbuffs: (only used for @group_style = PARSER_GROUP_MSG) array to store @@ -1096,7 +1096,14 @@ int nl_parser(struct nl_context *nlctx, const struct param_parser *params, buff = tmp_buff_find(buffs, parser->group); msgbuff = buff ? buff->msgbuff : &nlsk->msgbuff; - param_dest = dest ? ((char *)dest + parser->dest_offset) : NULL; + if (dest) { + unsigned long index = parser - params; + + param_dest = ((char *)dest + parser->dest_offset); + set_bit(index, (unsigned long *)dest); + } else { + param_dest = NULL; + } ret = parser->handler(nlctx, parser->type, parser->handler_data, msgbuff, param_dest); if (ret < 0) diff --git a/netlink/pse-pd.c b/netlink/pse-pd.c index d6faff8..2c8dd89 100644 --- a/netlink/pse-pd.c +++ b/netlink/pse-pd.c @@ -54,6 +54,41 @@ static const char *podl_pse_pw_d_status_name(u32 val) } } +static const char *c33_pse_admin_state_name(u32 val) +{ + switch (val) { + case ETHTOOL_C33_PSE_ADMIN_STATE_UNKNOWN: + return "unknown"; + case ETHTOOL_C33_PSE_ADMIN_STATE_DISABLED: + return "disabled"; + case ETHTOOL_C33_PSE_ADMIN_STATE_ENABLED: + return "enabled"; + default: + return "unsupported"; + } +} + +static const char *c33_pse_pw_d_status_name(u32 val) +{ + switch (val) { + case ETHTOOL_C33_PSE_PW_D_STATUS_UNKNOWN: + return "unknown"; + case ETHTOOL_C33_PSE_PW_D_STATUS_DISABLED: + return "disabled"; + case ETHTOOL_C33_PSE_PW_D_STATUS_SEARCHING: + return "searching"; + case ETHTOOL_C33_PSE_PW_D_STATUS_DELIVERING: + return "delivering power"; + case ETHTOOL_C33_PSE_PW_D_STATUS_TEST: + return "test"; + case ETHTOOL_C33_PSE_PW_D_STATUS_FAULT: + return "fault"; + case ETHTOOL_C33_PSE_PW_D_STATUS_OTHERFAULT: + return "otherfault"; + default: + return "unsupported"; + } +} int pse_reply_cb(const struct nlmsghdr *nlhdr, void *data) { const struct nlattr *tb[ETHTOOL_A_PSE_MAX + 1] = {}; @@ -98,6 +133,24 @@ int pse_reply_cb(const struct nlmsghdr *nlhdr, void *data) podl_pse_pw_d_status_name(val)); } + if (tb[ETHTOOL_A_C33_PSE_ADMIN_STATE]) { + u32 val; + + val = mnl_attr_get_u32(tb[ETHTOOL_A_C33_PSE_ADMIN_STATE]); + print_string(PRINT_ANY, "c33-pse-admin-state", + "Clause 33 PSE Admin State: %s\n", + c33_pse_admin_state_name(val)); + } + + if (tb[ETHTOOL_A_C33_PSE_PW_D_STATUS]) { + u32 val; + + val = mnl_attr_get_u32(tb[ETHTOOL_A_C33_PSE_PW_D_STATUS]); + print_string(PRINT_ANY, "c33-pse-power-detection-status", + "Clause 33 PSE Power Detection Status: %s\n", + c33_pse_pw_d_status_name(val)); + } + close_json_object(); return MNL_CB_OK; @@ -138,6 +191,12 @@ static const struct lookup_entry_u32 podl_pse_admin_control_values[] = { {} }; +static const struct lookup_entry_u32 c33_pse_admin_control_values[] = { + { .arg = "enable", .val = ETHTOOL_C33_PSE_ADMIN_STATE_ENABLED }, + { .arg = "disable", .val = ETHTOOL_C33_PSE_ADMIN_STATE_DISABLED }, + {} +}; + static const struct param_parser spse_params[] = { { .arg = "podl-pse-admin-control", @@ -146,6 +205,13 @@ static const struct param_parser spse_params[] = { .handler_data = podl_pse_admin_control_values, .min_argc = 1, }, + { + .arg = "c33-pse-admin-control", + .type = ETHTOOL_A_C33_PSE_ADMIN_CONTROL, + .handler = nl_parse_lookup_u32, + .handler_data = c33_pse_admin_control_values, + .min_argc = 1, + }, {} }; diff --git a/netlink/settings.c b/netlink/settings.c index a506618..9dd688b 100644 --- a/netlink/settings.c +++ b/netlink/settings.c @@ -11,6 +11,8 @@ #include "../internal.h" #include "../common.h" +#include "json_print.h" +#include "json_writer.h" #include "netlink.h" #include "strset.h" #include "bitset.h" @@ -192,15 +194,21 @@ static bool lm_class_match(unsigned int mode, enum link_mode_class class) } static void print_enum(const char *const *info, unsigned int n_info, - unsigned int val, const char *label) + unsigned int val, const char *label, const char *json_key) { - if (val >= n_info || !info[val]) - printf("\t%s: Unknown! (%d)\n", label, val); - else - printf("\t%s: %s\n", label, info[val]); + if (val >= n_info || !info[val]) { + if (!is_json_context()) + printf("\t%s: Unknown! (%d)\n", label, val); + } else { + if (!is_json_context()) + printf("\t%s: %s\n", label, info[val]); + else + print_string(PRINT_JSON, json_key, "%s", info[val]); + } } -static int dump_pause(const struct nlattr *attr, bool mask, const char *label) +static int dump_pause(const struct nlattr *attr, bool mask, const char *label, + const char *label_json) { bool pause, asym; int ret = 0; @@ -213,11 +221,13 @@ static int dump_pause(const struct nlattr *attr, bool mask, const char *label) if (ret < 0) goto err; - printf("\t%s", label); + if (!is_json_context()) + printf("\t%s", label); if (pause) - printf("%s\n", asym ? "Symmetric Receive-only" : "Symmetric"); + print_string(PRINT_ANY, label_json, "%s\n", + asym ? "Symmetric Receive-only" : "Symmetric"); else - printf("%s\n", asym ? "Transmit-only" : "No"); + print_string(PRINT_ANY, label_json, "%s\n", asym ? "Transmit-only" : "No"); return 0; err: @@ -229,13 +239,14 @@ static void print_banner(struct nl_context *nlctx) { if (nlctx->no_banner) return; - printf("Settings for %s:\n", nlctx->devname); + print_string(PRINT_ANY, "ifname", "Settings for %s:\n", nlctx->devname); nlctx->no_banner = true; } int dump_link_modes(struct nl_context *nlctx, const struct nlattr *bitset, bool mask, unsigned int class, const char *before, - const char *between, const char *after, const char *if_none) + const char *between, const char *after, const char *if_none, + const char *json_key) { const struct nlattr *bitset_tb[ETHTOOL_A_BITSET_MAX + 1] = {}; DECLARE_ATTR_TB_INFO(bitset_tb); @@ -260,6 +271,7 @@ int dump_link_modes(struct nl_context *nlctx, const struct nlattr *bitset, bits = bitset_tb[ETHTOOL_A_BITSET_BITS]; + open_json_array(json_key, ""); if (!bits) { const struct stringset *lm_strings; unsigned int count; @@ -280,7 +292,9 @@ int dump_link_modes(struct nl_context *nlctx, const struct nlattr *bitset, if (mnl_attr_get_payload_len(bits) / 4 < (count + 31) / 32) goto err_nonl; - printf("\t%s", before); + if (!is_json_context()) + printf("\t%s", before); + for (idx = 0; idx < count; idx++) { const uint32_t *raw_data = mnl_attr_get_payload(bits); char buff[14]; @@ -298,21 +312,27 @@ int dump_link_modes(struct nl_context *nlctx, const struct nlattr *bitset, first = false; /* ugly hack to preserve old output format */ if (class == LM_CLASS_REAL && (idx == prev + 1) && - prev < link_modes_count && - link_modes[prev].class == LM_CLASS_REAL && - link_modes[prev].duplex == DUPLEX_HALF) - putchar(' '); - else if (between) - printf("\t%s", between); + prev < link_modes_count && + link_modes[prev].class == LM_CLASS_REAL && + link_modes[prev].duplex == DUPLEX_HALF) { + if (!is_json_context()) + putchar(' '); + } else if (between) { + if (!is_json_context()) + printf("\t%s", between); + } else - printf("\n\t%*s", before_len, ""); - printf("%s", name); + if (!is_json_context()) + printf("\n\t%*s", before_len, ""); + print_string(PRINT_ANY, NULL, "%s", name); prev = idx; } goto after; } - printf("\t%s", before); + if (!is_json_context()) + printf("\t%s", before); + mnl_attr_for_each_nested(bit, bits) { const struct nlattr *tb[ETHTOOL_A_BITSET_BIT_MAX + 1] = {}; DECLARE_ATTR_TB_INFO(tb); @@ -342,27 +362,31 @@ int dump_link_modes(struct nl_context *nlctx, const struct nlattr *bitset, if ((class == LM_CLASS_REAL) && (idx == prev + 1) && (prev < link_modes_count) && (link_modes[prev].class == LM_CLASS_REAL) && - (link_modes[prev].duplex == DUPLEX_HALF)) - putchar(' '); - else if (between) - printf("\t%s", between); + (link_modes[prev].duplex == DUPLEX_HALF)) { + if (!is_json_context()) + putchar(' '); + } else if (between) { + if (!is_json_context()) + printf("\t%s", between); + } else - printf("\n\t%*s", before_len, ""); + if (!is_json_context()) + printf("\n\t%*s", before_len, ""); } - printf("%s", name); + print_string(PRINT_ANY, NULL, "%s", name); prev = idx; } after: if (first && if_none) - printf("%s", if_none); - printf("%s", after); - + print_string(PRINT_FP, NULL, "%s", if_none); + close_json_array(after); return 0; err: putchar('\n'); err_nonl: fflush(stdout); fprintf(stderr, "malformed netlink message (link_modes)\n"); + close_json_array(""); return ret; } @@ -373,16 +397,16 @@ static int dump_our_modes(struct nl_context *nlctx, const struct nlattr *attr) print_banner(nlctx); ret = dump_link_modes(nlctx, attr, true, LM_CLASS_PORT, - "Supported ports: [ ", " ", " ]\n", NULL); + "Supported ports: [ ", " ", " ]\n", NULL, "supported-ports"); if (ret < 0) return ret; ret = dump_link_modes(nlctx, attr, true, LM_CLASS_REAL, "Supported link modes: ", NULL, "\n", - "Not reported"); + "Not reported", "supported-link-modes"); if (ret < 0) return ret; - ret = dump_pause(attr, true, "Supported pause frame use: "); + ret = dump_pause(attr, true, "Supported pause frame use: ", "supported-pause-frame-use"); if (ret < 0) return ret; @@ -390,32 +414,40 @@ static int dump_our_modes(struct nl_context *nlctx, const struct nlattr *attr) &ret); if (ret < 0) return ret; - printf("\tSupports auto-negotiation: %s\n", autoneg ? "Yes" : "No"); + + if (is_json_context()) + print_bool(PRINT_JSON, "supports-auto-negotiation", NULL, autoneg); + else + printf("\tSupports auto-negotiation: %s\n", autoneg ? "Yes" : "No"); ret = dump_link_modes(nlctx, attr, true, LM_CLASS_FEC, "Supported FEC modes: ", " ", "\n", - "Not reported"); + "Not reported", "supported-fec-modes"); if (ret < 0) return ret; ret = dump_link_modes(nlctx, attr, false, LM_CLASS_REAL, "Advertised link modes: ", NULL, "\n", - "Not reported"); + "Not reported", "advertised-link-modes"); if (ret < 0) return ret; - ret = dump_pause(attr, false, "Advertised pause frame use: "); + ret = dump_pause(attr, false, "Advertised pause frame use: ", "advertised-pause-frame-use"); if (ret < 0) return ret; autoneg = bitset_get_bit(attr, false, ETHTOOL_LINK_MODE_Autoneg_BIT, &ret); if (ret < 0) return ret; - printf("\tAdvertised auto-negotiation: %s\n", autoneg ? "Yes" : "No"); + + if (!is_json_context()) + printf("\tAdvertised auto-negotiation: %s\n", autoneg ? "Yes" : "No"); + else + print_bool(PRINT_JSON, "advertised-auto-negotiation", NULL, autoneg); ret = dump_link_modes(nlctx, attr, false, LM_CLASS_FEC, "Advertised FEC modes: ", " ", "\n", - "Not reported"); + "Not reported", "advertised-fec-modes"); return ret; } @@ -427,12 +459,13 @@ static int dump_peer_modes(struct nl_context *nlctx, const struct nlattr *attr) print_banner(nlctx); ret = dump_link_modes(nlctx, attr, false, LM_CLASS_REAL, "Link partner advertised link modes: ", - NULL, "\n", "Not reported"); + NULL, "\n", "Not reported", "link-partner-advertised-link-modes"); if (ret < 0) return ret; ret = dump_pause(attr, false, - "Link partner advertised pause frame use: "); + "Link partner advertised pause frame use: ", + "link-partner-advertised-pause-frame-use"); if (ret < 0) return ret; @@ -440,12 +473,16 @@ static int dump_peer_modes(struct nl_context *nlctx, const struct nlattr *attr) ETHTOOL_LINK_MODE_Autoneg_BIT, &ret); if (ret < 0) return ret; - printf("\tLink partner advertised auto-negotiation: %s\n", - autoneg ? "Yes" : "No"); + + if (!is_json_context()) + print_string(PRINT_FP, NULL, "\tLink partner advertised auto-negotiation: %s\n", + autoneg ? "Yes" : "No"); + else + print_bool(PRINT_JSON, "link-partner-advertised-auto-negotiation", NULL, autoneg); ret = dump_link_modes(nlctx, attr, false, LM_CLASS_FEC, "Link partner advertised FEC modes: ", - " ", "\n", "Not reported"); + " ", "\n", "Not reported", "link-partner-advertised-fec-modes"); return ret; } @@ -479,30 +516,36 @@ int linkmodes_reply_cb(const struct nlmsghdr *nlhdr, void *data) uint32_t val = mnl_attr_get_u32(tb[ETHTOOL_A_LINKMODES_SPEED]); print_banner(nlctx); - if (val == 0 || val == (uint16_t)(-1) || val == (uint32_t)(-1)) - printf("\tSpeed: Unknown!\n"); - else - printf("\tSpeed: %uMb/s\n", val); + if (val == 0 || val == (uint16_t)(-1) || val == (uint32_t)(-1)) { + if (!is_json_context()) + printf("\tSpeed: Unknown!\n"); + } else { + print_uint(PRINT_ANY, "speed", "\tSpeed: %uMb/s\n", val); + } } if (tb[ETHTOOL_A_LINKMODES_LANES]) { uint32_t val = mnl_attr_get_u32(tb[ETHTOOL_A_LINKMODES_LANES]); print_banner(nlctx); - printf("\tLanes: %u\n", val); + print_uint(PRINT_ANY, "lanes", "\tLanes: %s\n", val); } if (tb[ETHTOOL_A_LINKMODES_DUPLEX]) { uint8_t val = mnl_attr_get_u8(tb[ETHTOOL_A_LINKMODES_DUPLEX]); print_banner(nlctx); print_enum(names_duplex, ARRAY_SIZE(names_duplex), val, - "Duplex"); + "Duplex", "duplex"); } if (tb[ETHTOOL_A_LINKMODES_AUTONEG]) { int autoneg = mnl_attr_get_u8(tb[ETHTOOL_A_LINKMODES_AUTONEG]); print_banner(nlctx); - printf("\tAuto-negotiation: %s\n", - (autoneg == AUTONEG_DISABLE) ? "off" : "on"); + if (!is_json_context()) + printf("\tAuto-negotiation: %s\n", + (autoneg == AUTONEG_DISABLE) ? "off" : "on"); + else + print_bool(PRINT_JSON, "auto-negotiation", NULL, + autoneg == AUTONEG_DISABLE); } if (tb[ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG]) { uint8_t val; @@ -512,7 +555,7 @@ int linkmodes_reply_cb(const struct nlmsghdr *nlhdr, void *data) print_banner(nlctx); print_enum(names_master_slave_cfg, ARRAY_SIZE(names_master_slave_cfg), val, - "master-slave cfg"); + "master-slave cfg", "master-slave-cfg"); } if (tb[ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE]) { uint8_t val; @@ -521,14 +564,14 @@ int linkmodes_reply_cb(const struct nlmsghdr *nlhdr, void *data) print_banner(nlctx); print_enum(names_master_slave_state, ARRAY_SIZE(names_master_slave_state), val, - "master-slave status"); + "master-slave status", "master-slave-status"); } return MNL_CB_OK; err: if (nlctx->is_monitor || nlctx->is_dump) return MNL_CB_OK; - fputs("No data available\n", stdout); + fputs("No data available\n", stderr); nlctx->exit_code = 75; return MNL_CB_ERROR; } @@ -554,14 +597,14 @@ int linkinfo_reply_cb(const struct nlmsghdr *nlhdr, void *data) uint8_t val = mnl_attr_get_u8(tb[ETHTOOL_A_LINKINFO_PORT]); print_banner(nlctx); - print_enum(names_port, ARRAY_SIZE(names_port), val, "Port"); + print_enum(names_port, ARRAY_SIZE(names_port), val, "Port", "port"); port = val; } if (tb[ETHTOOL_A_LINKINFO_PHYADDR]) { uint8_t val = mnl_attr_get_u8(tb[ETHTOOL_A_LINKINFO_PHYADDR]); print_banner(nlctx); - printf("\tPHYAD: %u\n", val); + print_uint(PRINT_ANY, "phyad", "\tPHYAD: %x\n", val); } if (tb[ETHTOOL_A_LINKINFO_TRANSCEIVER]) { uint8_t val; @@ -569,7 +612,7 @@ int linkinfo_reply_cb(const struct nlmsghdr *nlhdr, void *data) val = mnl_attr_get_u8(tb[ETHTOOL_A_LINKINFO_TRANSCEIVER]); print_banner(nlctx); print_enum(names_transceiver, ARRAY_SIZE(names_transceiver), - val, "Transceiver"); + val, "Transceiver", "transceiver"); } if (tb[ETHTOOL_A_LINKINFO_TP_MDIX] && tb[ETHTOOL_A_LINKINFO_TP_MDIX_CTRL] && port == PORT_TP) { @@ -714,9 +757,9 @@ static void linkstate_link_ext_substate_print(const struct nlattr *tb[], link_ext_substate_str = link_ext_substate_get(link_ext_state_val, link_ext_substate_val); if (!link_ext_substate_str) - printf(", %u", link_ext_substate_val); + print_uint(PRINT_ANY, NULL, ", %u", link_ext_state_val); else - printf(", %s", link_ext_substate_str); + print_string(PRINT_ANY, NULL, ", %s", link_ext_substate_str); } static void linkstate_link_ext_state_print(const struct nlattr *tb[]) @@ -732,13 +775,14 @@ static void linkstate_link_ext_state_print(const struct nlattr *tb[]) link_ext_state_str = get_enum_string(names_link_ext_state, ARRAY_SIZE(names_link_ext_state), link_ext_state_val); + open_json_array("link-state", ""); if (!link_ext_state_str) - printf(" (%u", link_ext_state_val); + print_uint(PRINT_ANY, NULL, " (%u", link_ext_state_val); else - printf(" (%s", link_ext_state_str); + print_string(PRINT_ANY, NULL, " (%s", link_ext_state_str); linkstate_link_ext_substate_print(tb, link_ext_state_val); - printf(")"); + close_json_array(")"); } int linkstate_reply_cb(const struct nlmsghdr *nlhdr, void *data) @@ -761,24 +805,29 @@ int linkstate_reply_cb(const struct nlmsghdr *nlhdr, void *data) uint8_t val = mnl_attr_get_u8(tb[ETHTOOL_A_LINKSTATE_LINK]); print_banner(nlctx); - printf("\tLink detected: %s", val ? "yes" : "no"); + if (!is_json_context()) + print_string(PRINT_FP, NULL, "\tLink detected: %s", val ? "yes" : "no"); + else + print_bool(PRINT_JSON, "link-detected", NULL, val); linkstate_link_ext_state_print(tb); - printf("\n"); + if (!is_json_context()) + printf("\n"); } if (tb[ETHTOOL_A_LINKSTATE_SQI]) { uint32_t val = mnl_attr_get_u32(tb[ETHTOOL_A_LINKSTATE_SQI]); print_banner(nlctx); - printf("\tSQI: %u", val); + print_uint(PRINT_ANY, "sqi", "\tSQI: %u", val); if (tb[ETHTOOL_A_LINKSTATE_SQI_MAX]) { uint32_t max; max = mnl_attr_get_u32(tb[ETHTOOL_A_LINKSTATE_SQI_MAX]); - printf("/%u\n", max); + print_uint(PRINT_ANY, "sqi-max", "/%u\n", max); } else { - printf("\n"); + if (!is_json_context()) + printf("\n"); } } @@ -786,7 +835,7 @@ int linkstate_reply_cb(const struct nlmsghdr *nlhdr, void *data) uint32_t val; val = mnl_attr_get_u32(tb[ETHTOOL_A_LINKSTATE_EXT_DOWN_CNT]); - printf("\tLink Down Events: %u\n", val); + print_uint(PRINT_ANY, "link-down-events", "\tLink Down Events: %u\n", val); } return MNL_CB_OK; @@ -856,7 +905,7 @@ void msgmask_cb2(unsigned int idx __maybe_unused, const char *name, bool val, void *data __maybe_unused) { if (val) - printf(" %s", name); + print_string(PRINT_FP, NULL, " %s", name); } int debug_reply_cb(const struct nlmsghdr *nlhdr, void *data) @@ -889,13 +938,16 @@ int debug_reply_cb(const struct nlmsghdr *nlhdr, void *data) print_banner(nlctx); walk_bitset(tb[ETHTOOL_A_DEBUG_MSGMASK], NULL, msgmask_cb, &msg_mask); - printf(" Current message level: 0x%08x (%u)\n" - " ", - msg_mask, msg_mask); + + print_uint(PRINT_ANY, "current-message-level", + " Current message level: 0x%1$08x (%1$u)\n ", + msg_mask); + walk_bitset(tb[ETHTOOL_A_DEBUG_MSGMASK], msgmask_strings, msgmask_cb2, - NULL); - fputc('\n', stdout); + NULL); + if (!is_json_context()) + fputc('\n', stdout); return MNL_CB_OK; } @@ -916,18 +968,26 @@ int plca_cfg_reply_cb(const struct nlmsghdr *nlhdr, void *data) return MNL_CB_OK; print_banner(nlctx); - printf("\tPLCA support: "); + if (!is_json_context()) + printf("\tPLCA support: "); if (tb[ETHTOOL_A_PLCA_VERSION]) { uint16_t val = mnl_attr_get_u16(tb[ETHTOOL_A_PLCA_VERSION]); - printf("OPEN Alliance v%u.%u", - (unsigned int)((val >> 4) & 0xF), - (unsigned int)(val & 0xF)); - } else - printf("non-standard"); + if (!is_json_context()) { + printf("OPEN Alliance v%u.%u\n", + (unsigned int)((val >> 4) & 0xF), + (unsigned int)(val & 0xF)); + } else { + unsigned int length = snprintf(NULL, 0, "%1$u.%1$u", val); + char buff[length]; - printf("\n"); + snprintf(buff, length, "%u.%u", (unsigned int)((val >> 4) & 0xF), + (unsigned int)(val & 0xF)); + print_string(PRINT_JSON, "open-alliance-v", NULL, buff); + } + } else + print_string(PRINT_ANY, "plca-support", "%s\n", "non-standard"); return MNL_CB_OK; } @@ -949,16 +1009,14 @@ int plca_status_reply_cb(const struct nlmsghdr *nlhdr, void *data) return MNL_CB_OK; print_banner(nlctx); - printf("\tPLCA status: "); - + const char *status; if (tb[ETHTOOL_A_PLCA_STATUS]) { uint8_t val = mnl_attr_get_u8(tb[ETHTOOL_A_PLCA_STATUS]); - - printf(val ? "up" : "down"); - } else - printf("unknown"); - - printf("\n"); + status = val ? "up" : "down"; + print_string(PRINT_ANY, "plca-status", "PLCA status: %s", status); + } else { + print_string(PRINT_FP, NULL, "PLCA status: %s", "unknown"); + } return MNL_CB_OK; } @@ -984,7 +1042,10 @@ static int gset_request(struct cmd_context *ctx, uint8_t msg_type, int nl_gset(struct cmd_context *ctx) { - int ret; + int ret = 0; + + new_json_obj(ctx->json); + open_json_object(NULL); /* Check for the base set of commands */ if (netlink_cmd_check(ctx, ETHTOOL_MSG_LINKMODES_GET, true) || @@ -999,44 +1060,50 @@ int nl_gset(struct cmd_context *ctx) ret = gset_request(ctx, ETHTOOL_MSG_LINKMODES_GET, ETHTOOL_A_LINKMODES_HEADER, linkmodes_reply_cb); if (ret == -ENODEV) - return ret; + goto out; ret = gset_request(ctx, ETHTOOL_MSG_LINKINFO_GET, ETHTOOL_A_LINKINFO_HEADER, linkinfo_reply_cb); if (ret == -ENODEV) - return ret; + goto out; ret = gset_request(ctx, ETHTOOL_MSG_WOL_GET, ETHTOOL_A_WOL_HEADER, wol_reply_cb); if (ret == -ENODEV) - return ret; + goto out; ret = gset_request(ctx, ETHTOOL_MSG_PLCA_GET_CFG, ETHTOOL_A_PLCA_HEADER, plca_cfg_reply_cb); if (ret == -ENODEV) - return ret; + goto out; ret = gset_request(ctx, ETHTOOL_MSG_DEBUG_GET, ETHTOOL_A_DEBUG_HEADER, debug_reply_cb); if (ret == -ENODEV) - return ret; + goto out; ret = gset_request(ctx, ETHTOOL_MSG_LINKSTATE_GET, ETHTOOL_A_LINKSTATE_HEADER, linkstate_reply_cb); if (ret == -ENODEV) - return ret; + goto out; ret = gset_request(ctx, ETHTOOL_MSG_PLCA_GET_STATUS, ETHTOOL_A_PLCA_HEADER, plca_status_reply_cb); if (ret == -ENODEV) - return ret; + goto out; if (!ctx->nlctx->no_banner) { - printf("No data available\n"); - return 75; + print_string(PRINT_FP, NULL, "%s", "No data available\n"); + ret = 75; + goto out; } - return 0; + ret = 0; + +out: + close_json_object(); + delete_json_obj(); + return ret; } /* SET_SETTINGS */ diff --git a/netlink/tsinfo.c b/netlink/tsinfo.c index c6571ff..4df4141 100644 --- a/netlink/tsinfo.c +++ b/netlink/tsinfo.c @@ -5,6 +5,7 @@ */ #include <errno.h> +#include <inttypes.h> #include <string.h> #include <stdio.h> @@ -15,6 +16,60 @@ /* TSINFO_GET */ +static int tsinfo_show_stats(const struct nlattr *nest) +{ + const struct nlattr *tb[ETHTOOL_A_TS_STAT_MAX + 1] = {}; + DECLARE_ATTR_TB_INFO(tb); + static const struct { + unsigned int attr; + char *name; + } stats[] = { + { ETHTOOL_A_TS_STAT_TX_PKTS, "tx_pkts" }, + { ETHTOOL_A_TS_STAT_TX_LOST, "tx_lost" }, + { ETHTOOL_A_TS_STAT_TX_ERR, "tx_err" }, + }; + bool header = false; + unsigned int i; + __u64 val; + int ret; + + ret = mnl_attr_parse_nested(nest, attr_cb, &tb_info); + if (ret < 0) + return ret; + + open_json_object("statistics"); + for (i = 0; i < ARRAY_SIZE(stats); i++) { + char fmt[64]; + + if (!tb[stats[i].attr]) + continue; + + if (!header && !is_json_context()) { + printf("Statistics:\n"); + header = true; + } + + if (!mnl_attr_validate(tb[stats[i].attr], MNL_TYPE_U32)) { + val = mnl_attr_get_u32(tb[stats[i].attr]); + } else if (!mnl_attr_validate(tb[stats[i].attr], MNL_TYPE_U64)) { + val = mnl_attr_get_u64(tb[stats[i].attr]); + } else { + fprintf(stderr, "malformed netlink message (statistic)\n"); + goto err_close_stats; + } + + snprintf(fmt, sizeof(fmt), " %s: %%" PRIu64 "\n", stats[i].name); + print_u64(PRINT_ANY, stats[i].name, fmt, val); + } + close_json_object(); + + return 0; + +err_close_stats: + close_json_object(); + return -1; +} + static void tsinfo_dump_cb(unsigned int idx, const char *name, bool val, void *data __maybe_unused) { @@ -99,6 +154,12 @@ int tsinfo_reply_cb(const struct nlmsghdr *nlhdr, void *data) if (ret < 0) return err_ret; + if (tb[ETHTOOL_A_TSINFO_STATS]) { + ret = tsinfo_show_stats(tb[ETHTOOL_A_TSINFO_STATS]); + if (ret < 0) + return err_ret; + } + return MNL_CB_OK; } @@ -106,6 +167,7 @@ int nl_tsinfo(struct cmd_context *ctx) { struct nl_context *nlctx = ctx->nlctx; struct nl_socket *nlsk = nlctx->ethnl_socket; + u32 flags; int ret; if (netlink_cmd_check(ctx, ETHTOOL_MSG_TSINFO_GET, true)) @@ -116,8 +178,9 @@ int nl_tsinfo(struct cmd_context *ctx) return 1; } + flags = get_stats_flag(nlctx, ETHTOOL_MSG_TSINFO_GET, ETHTOOL_A_TSINFO_HEADER); ret = nlsock_prep_get_request(nlsk, ETHTOOL_MSG_TSINFO_GET, - ETHTOOL_A_TSINFO_HEADER, 0); + ETHTOOL_A_TSINFO_HEADER, flags); if (ret < 0) return ret; return nlsock_send_get_request(nlsk, tsinfo_reply_cb); |