diff options
Diffstat (limited to '')
-rw-r--r-- | Makefile.am | 4 | ||||
-rw-r--r-- | NEWS | 11 | ||||
-rw-r--r-- | common.c | 70 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | ethtool.8.in | 2 | ||||
-rw-r--r-- | ethtool.c | 23 | ||||
-rw-r--r-- | netlink/eee.c | 41 | ||||
-rw-r--r-- | netlink/module-eeprom.c | 30 | ||||
-rw-r--r-- | netlink/netlink.h | 2 | ||||
-rw-r--r-- | netlink/parser.c | 11 | ||||
-rw-r--r-- | netlink/pse-pd.c | 66 | ||||
-rw-r--r-- | netlink/settings.c | 269 | ||||
-rw-r--r-- | netlink/tsinfo.c | 65 | ||||
-rw-r--r-- | qsfp.c | 11 | ||||
-rw-r--r-- | test-cmdline.c | 1 | ||||
-rw-r--r-- | uapi/linux/ethtool.h | 55 | ||||
-rw-r--r-- | uapi/linux/ethtool_netlink.h | 32 | ||||
-rw-r--r-- | uapi/linux/if_link.h | 3 | ||||
-rw-r--r-- | uapi/linux/stddef.h | 8 |
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: @@ -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) @@ -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 . @@ -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); @@ -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 */ |