summaryrefslogtreecommitdiffstats
path: root/netlink
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-08-26 10:34:19 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-08-26 10:34:19 +0000
commit942dc614706293cdedc7dede7dc09d8fdf9583f2 (patch)
tree39a8bf3ebede54ce9aea189de4036398199ee6e9 /netlink
parentAdding upstream version 1:6.9. (diff)
downloadethtool-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.c41
-rw-r--r--netlink/module-eeprom.c30
-rw-r--r--netlink/netlink.h2
-rw-r--r--netlink/parser.c11
-rw-r--r--netlink/pse-pd.c66
-rw-r--r--netlink/settings.c269
-rw-r--r--netlink/tsinfo.c65
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);