diff options
Diffstat (limited to 'netlink/settings.c')
-rw-r--r-- | netlink/settings.c | 269 |
1 files changed, 168 insertions, 101 deletions
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 */ |