summaryrefslogtreecommitdiffstats
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
parentAdding upstream version 1:6.9. (diff)
downloadethtool-942dc614706293cdedc7dede7dc09d8fdf9583f2.tar.xz
ethtool-942dc614706293cdedc7dede7dc09d8fdf9583f2.zip
Adding upstream version 1:6.10.upstream/1%6.10upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--Makefile.am4
-rw-r--r--NEWS11
-rw-r--r--common.c70
-rw-r--r--configure.ac2
-rw-r--r--ethtool.8.in2
-rw-r--r--ethtool.c23
-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
-rw-r--r--qsfp.c11
-rw-r--r--test-cmdline.c1
-rw-r--r--uapi/linux/ethtool.h55
-rw-r--r--uapi/linux/ethtool_netlink.h32
-rw-r--r--uapi/linux/if_link.h3
-rw-r--r--uapi/linux/stddef.h8
19 files changed, 543 insertions, 163 deletions
diff --git a/Makefile.am b/Makefile.am
index b9e06ad..5a61a9a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -59,12 +59,12 @@ endif
TESTS = test-cmdline
check_PROGRAMS = test-cmdline
test_cmdline_SOURCES = test-cmdline.c test-common.c $(ethtool_SOURCES)
-test_cmdline_CFLAGS = -DTEST_ETHTOOL
+test_cmdline_CFLAGS = -D_POSIX_C_SOURCE=200809L -DTEST_ETHTOOL
if !ETHTOOL_ENABLE_NETLINK
TESTS += test-features
check_PROGRAMS += test-features
test_features_SOURCES = test-features.c test-common.c $(ethtool_SOURCES)
-test_features_CFLAGS = -DTEST_ETHTOOL
+test_features_CFLAGS = -D_POSIX_C_SOURCE=200809L -DTEST_ETHTOOL
endif
dist-hook:
diff --git a/NEWS b/NEWS
index 10b4859..23e6e3c 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,14 @@
+Version 6.10 - August 9, 2024
+ * Feature: suport for PoE in PSE (--show-pse and --set-pse)
+ * Feature: add statistics support to tsinfo (-T)
+ * Feature: add JSON output to base command (no option)
+ * Feature: add JSON output to EEE info (--show-eee)
+ * Fix: qsfp: better handling on page 03h read failure (-m)
+ * Fix: handle zero arguments for module eeprom dump (-m)
+ * Fix: check for missing arguments in do_srxfh() (-X)
+ * Misc: compiler warnings in "make check"
+ * Misc: more descriptive error when JSON output is not available
+
Version 6.9 - May 23, 2024
* Feature: support for rx-flow-hash gtp (-N)
* Feature: support for RSS input transformation (-X)
diff --git a/common.c b/common.c
index b8fd4d5..4fda4b4 100644
--- a/common.c
+++ b/common.c
@@ -5,6 +5,7 @@
*/
#include "internal.h"
+#include "json_print.h"
#include "common.h"
#ifndef HAVE_NETIF_MSG
@@ -129,21 +130,28 @@ static char *unparse_wolopts(int wolopts)
int dump_wol(struct ethtool_wolinfo *wol)
{
- fprintf(stdout, " Supports Wake-on: %s\n",
- unparse_wolopts(wol->supported));
- fprintf(stdout, " Wake-on: %s\n",
- unparse_wolopts(wol->wolopts));
+ print_string(PRINT_ANY, "supports-wake-on",
+ " Supports Wake-on: %s\n", unparse_wolopts(wol->supported));
+ print_string(PRINT_ANY, "wake-on",
+ " Wake-on: %s\n", unparse_wolopts(wol->wolopts));
+
if (wol->supported & WAKE_MAGICSECURE) {
int i;
int delim = 0;
- fprintf(stdout, " SecureOn password: ");
+ open_json_array("secureon-password", "");
+ if (!is_json_context())
+ fprintf(stdout, " SecureOn password: ");
for (i = 0; i < SOPASS_MAX; i++) {
- fprintf(stdout, "%s%02x", delim ? ":" : "",
- wol->sopass[i]);
+ __u8 sopass = wol->sopass[i];
+
+ if (!is_json_context())
+ fprintf(stdout, "%s%02x", delim ? ":" : "", sopass);
+ else
+ print_hex(PRINT_JSON, NULL, "%02u", sopass);
delim = 1;
}
- fprintf(stdout, "\n");
+ close_json_array("\n");
}
return 0;
@@ -151,26 +159,50 @@ int dump_wol(struct ethtool_wolinfo *wol)
void dump_mdix(u8 mdix, u8 mdix_ctrl)
{
- fprintf(stdout, " MDI-X: ");
+ bool mdi_x = false;
+ bool mdi_x_forced = false;
+ bool mdi_x_auto = false;
+
if (mdix_ctrl == ETH_TP_MDI) {
- fprintf(stdout, "off (forced)\n");
+ mdi_x = false;
+ mdi_x_forced = true;
} else if (mdix_ctrl == ETH_TP_MDI_X) {
- fprintf(stdout, "on (forced)\n");
+ mdi_x = true;
+ mdi_x_forced = true;
} else {
switch (mdix) {
- case ETH_TP_MDI:
- fprintf(stdout, "off");
- break;
case ETH_TP_MDI_X:
- fprintf(stdout, "on");
+ mdi_x = true;
break;
default:
- fprintf(stdout, "Unknown");
- break;
+ print_string(PRINT_FP, NULL, "\tMDI-X: %s\n", "Unknown");
+ return;
}
if (mdix_ctrl == ETH_TP_MDI_AUTO)
- fprintf(stdout, " (auto)");
- fprintf(stdout, "\n");
+ mdi_x_auto = true;
+ }
+
+ if (is_json_context()) {
+ print_bool(PRINT_JSON, "mdi-x", NULL, mdi_x);
+ print_bool(PRINT_JSON, "mdi-x-forced", NULL, mdi_x_forced);
+ print_bool(PRINT_JSON, "mdi-x-auto", NULL, mdi_x_auto);
+ } else {
+ fprintf(stdout, " MDI-X: ");
+ if (mdi_x_forced) {
+ if (mdi_x)
+ fprintf(stdout, "on (forced)\n");
+ else
+ fprintf(stdout, "off (forced)\n");
+ } else {
+ if (mdi_x)
+ fprintf(stdout, "on");
+ else
+ fprintf(stdout, "off");
+
+ if (mdi_x_auto)
+ fprintf(stdout, " (auto)");
+ fprintf(stdout, "\n");
+ }
}
}
diff --git a/configure.ac b/configure.ac
index e494aac..f6fe260 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
dnl Process this file with autoconf to produce a configure script.
-AC_INIT(ethtool, 6.9, netdev@vger.kernel.org)
+AC_INIT(ethtool, 6.10, netdev@vger.kernel.org)
AC_PREREQ(2.52)
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_SRCDIR([ethtool.c])
diff --git a/ethtool.8.in b/ethtool.8.in
index 8090f0f..c798cc2 100644
--- a/ethtool.8.in
+++ b/ethtool.8.in
@@ -117,7 +117,7 @@
. hy \\n(HY
..
.
-.TH ETHTOOL 8 "May 2024" "Ethtool version @VERSION@"
+.TH ETHTOOL 8 "August 2024" "Ethtool version @VERSION@"
.SH NAME
ethtool \- query or control network driver and hardware settings
.
diff --git a/ethtool.c b/ethtool.c
index e587597..1e0a349 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -70,6 +70,18 @@ static void exit_bad_args(void)
exit(1);
}
+static void exit_bad_args_info(const char *info) __attribute__((noreturn));
+
+static void exit_bad_args_info(const char *info)
+{
+ fprintf(stderr,
+ "ethtool: bad command line argument(s)\n"
+ "%s\n"
+ "For more information run ethtool -h\n",
+ info);
+ exit(1);
+}
+
static void exit_nlonly_param(const char *name) __attribute__((noreturn));
static void exit_nlonly_param(const char *name)
@@ -4261,6 +4273,8 @@ static int do_srxfh(struct cmd_context *ctx)
++arg_num;
} else if (!strcmp(ctx->argp[arg_num], "xfrm")) {
++arg_num;
+ if (!ctx->argp[arg_num])
+ exit_bad_args();
if (!strcmp(ctx->argp[arg_num], "symmetric-xor"))
req_input_xfrm = RXH_XFRM_SYM_XOR;
else if (!strcmp(ctx->argp[arg_num], "none"))
@@ -4270,6 +4284,8 @@ static int do_srxfh(struct cmd_context *ctx)
++arg_num;
} else if (!strcmp(ctx->argp[arg_num], "context")) {
++arg_num;
+ if (!ctx->argp[arg_num])
+ exit_bad_args();
if(!strcmp(ctx->argp[arg_num], "new"))
rss_context = ETH_RXFH_CONTEXT_ALLOC;
else
@@ -5731,6 +5747,7 @@ static const struct option args[] = {
{
/* "default" entry when no switch is used */
.opts = "",
+ .json = true,
.func = do_gset,
.nlfunc = nl_gset,
.help = "Display standard information about device",
@@ -6040,6 +6057,7 @@ static const struct option args[] = {
},
{
.opts = "--show-eee",
+ .json = true,
.func = do_geee,
.nlfunc = nl_geee,
.help = "Show EEE settings",
@@ -6216,6 +6234,7 @@ static const struct option args[] = {
.nlfunc = nl_spse,
.help = "Set Power Sourcing Equipment settings",
.xhelp = " [ podl-pse-admin-control enable|disable ]\n"
+ " [ c33-pse-admin-control enable|disable ]\n"
},
{
.opts = "-h|--help",
@@ -6555,13 +6574,13 @@ int main(int argc, char **argp)
exit_bad_args();
}
if (ctx.json && !args[k].json)
- exit_bad_args();
+ exit_bad_args_info("JSON output not available for this subcommand");
ctx.argc = argc;
ctx.argp = argp;
netlink_run_handler(&ctx, args[k].nlchk, args[k].nlfunc, !args[k].func);
if (ctx.json) /* no IOCTL command supports JSON output */
- exit_bad_args();
+ exit_nlonly_param("--json");
ret = ioctl_init(&ctx, args[k].no_dev);
if (ret)
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);
diff --git a/qsfp.c b/qsfp.c
index a2921fb..a3a919d 100644
--- a/qsfp.c
+++ b/qsfp.c
@@ -1038,8 +1038,15 @@ sff8636_memory_map_init_pages(struct cmd_context *ctx,
sff8636_request_init(&request, 0x3, SFF8636_PAGE_SIZE);
ret = nl_get_eeprom_page(ctx, &request);
- if (ret < 0)
- return ret;
+ if (ret < 0) {
+ /* Page 03h is not available due to a bug in the driver.
+ * This is a non-fatal error and sff8636_dom_parse()
+ * handles this correctly.
+ */
+ fprintf(stderr, "Failed to read Upper Page 03h, driver error?\n");
+ return 0;
+ }
+
map->page_03h = request.data - SFF8636_PAGE_SIZE;
return 0;
diff --git a/test-cmdline.c b/test-cmdline.c
index cb803ed..c48be87 100644
--- a/test-cmdline.c
+++ b/test-cmdline.c
@@ -25,6 +25,7 @@ static struct test_case {
{ 1, "" },
{ 0, "devname" },
{ 0, "15_char_devname" },
+ { !IS_NL, "--json devname" },
/* netlink interface allows names up to 127 characters */
{ !IS_NL, "16_char_devname!" },
{ !IS_NL, "127_char_devname0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde" },
diff --git a/uapi/linux/ethtool.h b/uapi/linux/ethtool.h
index 4d74ba0..bcec30c 100644
--- a/uapi/linux/ethtool.h
+++ b/uapi/linux/ethtool.h
@@ -751,6 +751,61 @@ enum ethtool_module_power_mode {
};
/**
+ * enum ethtool_pse_types - Types of PSE controller.
+ * @ETHTOOL_PSE_UNKNOWN: Type of PSE controller is unknown
+ * @ETHTOOL_PSE_PODL: PSE controller which support PoDL
+ * @ETHTOOL_PSE_C33: PSE controller which support Clause 33 (PoE)
+ */
+enum ethtool_pse_types {
+ ETHTOOL_PSE_UNKNOWN = 1 << 0,
+ ETHTOOL_PSE_PODL = 1 << 1,
+ ETHTOOL_PSE_C33 = 1 << 2,
+};
+
+/**
+ * enum ethtool_c33_pse_admin_state - operational state of the PoDL PSE
+ * functions. IEEE 802.3-2022 30.9.1.1.2 aPSEAdminState
+ * @ETHTOOL_C33_PSE_ADMIN_STATE_UNKNOWN: state of PSE functions is unknown
+ * @ETHTOOL_C33_PSE_ADMIN_STATE_DISABLED: PSE functions are disabled
+ * @ETHTOOL_C33_PSE_ADMIN_STATE_ENABLED: PSE functions are enabled
+ */
+enum ethtool_c33_pse_admin_state {
+ ETHTOOL_C33_PSE_ADMIN_STATE_UNKNOWN = 1,
+ ETHTOOL_C33_PSE_ADMIN_STATE_DISABLED,
+ ETHTOOL_C33_PSE_ADMIN_STATE_ENABLED,
+};
+
+/**
+ * enum ethtool_c33_pse_pw_d_status - power detection status of the PSE.
+ * IEEE 802.3-2022 30.9.1.1.3 aPoDLPSEPowerDetectionStatus:
+ * @ETHTOOL_C33_PSE_PW_D_STATUS_UNKNOWN: PSE status is unknown
+ * @ETHTOOL_C33_PSE_PW_D_STATUS_DISABLED: The enumeration "disabled"
+ * indicates that the PSE State diagram is in the state DISABLED.
+ * @ETHTOOL_C33_PSE_PW_D_STATUS_SEARCHING: The enumeration "searching"
+ * indicates the PSE State diagram is in a state other than those
+ * listed.
+ * @ETHTOOL_C33_PSE_PW_D_STATUS_DELIVERING: The enumeration
+ * "deliveringPower" indicates that the PSE State diagram is in the
+ * state POWER_ON.
+ * @ETHTOOL_C33_PSE_PW_D_STATUS_TEST: The enumeration "test" indicates that
+ * the PSE State diagram is in the state TEST_MODE.
+ * @ETHTOOL_C33_PSE_PW_D_STATUS_FAULT: The enumeration "fault" indicates that
+ * the PSE State diagram is in the state TEST_ERROR.
+ * @ETHTOOL_C33_PSE_PW_D_STATUS_OTHERFAULT: The enumeration "otherFault"
+ * indicates that the PSE State diagram is in the state IDLE due to
+ * the variable error_condition = true.
+ */
+enum ethtool_c33_pse_pw_d_status {
+ ETHTOOL_C33_PSE_PW_D_STATUS_UNKNOWN = 1,
+ ETHTOOL_C33_PSE_PW_D_STATUS_DISABLED,
+ ETHTOOL_C33_PSE_PW_D_STATUS_SEARCHING,
+ ETHTOOL_C33_PSE_PW_D_STATUS_DELIVERING,
+ ETHTOOL_C33_PSE_PW_D_STATUS_TEST,
+ ETHTOOL_C33_PSE_PW_D_STATUS_FAULT,
+ ETHTOOL_C33_PSE_PW_D_STATUS_OTHERFAULT,
+};
+
+/**
* enum ethtool_podl_pse_admin_state - operational state of the PoDL PSE
* functions. IEEE 802.3-2018 30.15.1.1.2 aPoDLPSEAdminState
* @ETHTOOL_PODL_PSE_ADMIN_STATE_UNKNOWN: state of PoDL PSE functions are
diff --git a/uapi/linux/ethtool_netlink.h b/uapi/linux/ethtool_netlink.h
index 447d922..c0be6e5 100644
--- a/uapi/linux/ethtool_netlink.h
+++ b/uapi/linux/ethtool_netlink.h
@@ -117,12 +117,11 @@ enum {
/* request header */
-/* use compact bitsets in reply */
-#define ETHTOOL_FLAG_COMPACT_BITSETS (1 << 0)
-/* provide optional reply for SET or ACT requests */
-#define ETHTOOL_FLAG_OMIT_REPLY (1 << 1)
-/* request statistics, if supported by the driver */
-#define ETHTOOL_FLAG_STATS (1 << 2)
+enum ethtool_header_flags {
+ ETHTOOL_FLAG_COMPACT_BITSETS = 1 << 0, /* use compact bitsets in reply */
+ ETHTOOL_FLAG_OMIT_REPLY = 1 << 1, /* provide optional reply for SET or ACT requests */
+ ETHTOOL_FLAG_STATS = 1 << 2, /* request statistics, if supported by the driver */
+};
#define ETHTOOL_FLAG_ALL (ETHTOOL_FLAG_COMPACT_BITSETS | \
ETHTOOL_FLAG_OMIT_REPLY | \
@@ -478,12 +477,26 @@ enum {
ETHTOOL_A_TSINFO_TX_TYPES, /* bitset */
ETHTOOL_A_TSINFO_RX_FILTERS, /* bitset */
ETHTOOL_A_TSINFO_PHC_INDEX, /* u32 */
+ ETHTOOL_A_TSINFO_STATS, /* nest - _A_TSINFO_STAT */
/* add new constants above here */
__ETHTOOL_A_TSINFO_CNT,
ETHTOOL_A_TSINFO_MAX = (__ETHTOOL_A_TSINFO_CNT - 1)
};
+enum {
+ ETHTOOL_A_TS_STAT_UNSPEC,
+
+ ETHTOOL_A_TS_STAT_TX_PKTS, /* uint */
+ ETHTOOL_A_TS_STAT_TX_LOST, /* uint */
+ ETHTOOL_A_TS_STAT_TX_ERR, /* uint */
+
+ /* add new constants above here */
+ __ETHTOOL_A_TS_STAT_CNT,
+ ETHTOOL_A_TS_STAT_MAX = (__ETHTOOL_A_TS_STAT_CNT - 1)
+
+};
+
/* PHC VCLOCKS */
enum {
@@ -515,6 +528,10 @@ enum {
ETHTOOL_A_CABLE_RESULT_CODE_OPEN,
ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT,
ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT,
+ /* detected reflection caused by the impedance discontinuity between
+ * a regular 100 Ohm cable and a part with the abnormal impedance value
+ */
+ ETHTOOL_A_CABLE_RESULT_CODE_IMPEDANCE_MISMATCH,
};
enum {
@@ -895,6 +912,9 @@ enum {
ETHTOOL_A_PODL_PSE_ADMIN_STATE, /* u32 */
ETHTOOL_A_PODL_PSE_ADMIN_CONTROL, /* u32 */
ETHTOOL_A_PODL_PSE_PW_D_STATUS, /* u32 */
+ ETHTOOL_A_C33_PSE_ADMIN_STATE, /* u32 */
+ ETHTOOL_A_C33_PSE_ADMIN_CONTROL, /* u32 */
+ ETHTOOL_A_C33_PSE_PW_D_STATUS, /* u32 */
/* add new constants above here */
__ETHTOOL_A_PSE_CNT,
diff --git a/uapi/linux/if_link.h b/uapi/linux/if_link.h
index ff4ceea..987efed 100644
--- a/uapi/linux/if_link.h
+++ b/uapi/linux/if_link.h
@@ -1464,6 +1464,8 @@ enum {
IFLA_GTP_ROLE,
IFLA_GTP_CREATE_SOCKETS,
IFLA_GTP_RESTART_COUNT,
+ IFLA_GTP_LOCAL,
+ IFLA_GTP_LOCAL6,
__IFLA_GTP_MAX,
};
#define IFLA_GTP_MAX (__IFLA_GTP_MAX - 1)
@@ -1769,6 +1771,7 @@ enum {
IFLA_HSR_PROTOCOL, /* Indicate different protocol than
* HSR. For example PRP.
*/
+ IFLA_HSR_INTERLINK, /* HSR interlink network device */
__IFLA_HSR_MAX,
};
diff --git a/uapi/linux/stddef.h b/uapi/linux/stddef.h
index bf9749d..96aa341 100644
--- a/uapi/linux/stddef.h
+++ b/uapi/linux/stddef.h
@@ -55,4 +55,12 @@
#define __counted_by(m)
#endif
+#ifndef __counted_by_le
+#define __counted_by_le(m)
+#endif
+
+#ifndef __counted_by_be
+#define __counted_by_be(m)
+#endif
+
#endif /* _LINUX_STDDEF_H */