aboutsummaryrefslogtreecommitdiff
path: root/ethtool.c
diff options
context:
space:
mode:
Diffstat (limited to 'ethtool.c')
-rw-r--r--ethtool.c1966
1 files changed, 1344 insertions, 622 deletions
diff --git a/ethtool.c b/ethtool.c
index acf183d..af51220 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -31,6 +31,7 @@
#include "internal.h"
#include <string.h>
+#include <strings.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <stdio.h>
@@ -40,42 +41,23 @@
#include <sys/utsname.h>
#include <limits.h>
#include <ctype.h>
+#include <inttypes.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+#include <linux/ioctl.h>
#include <linux/sockios.h>
#include <linux/netlink.h>
+#include "common.h"
+#include "netlink/extapi.h"
+
#ifndef MAX_ADDR_LEN
#define MAX_ADDR_LEN 32
#endif
-#ifndef HAVE_NETIF_MSG
-enum {
- NETIF_MSG_DRV = 0x0001,
- NETIF_MSG_PROBE = 0x0002,
- NETIF_MSG_LINK = 0x0004,
- NETIF_MSG_TIMER = 0x0008,
- NETIF_MSG_IFDOWN = 0x0010,
- NETIF_MSG_IFUP = 0x0020,
- NETIF_MSG_RX_ERR = 0x0040,
- NETIF_MSG_TX_ERR = 0x0080,
- NETIF_MSG_TX_QUEUED = 0x0100,
- NETIF_MSG_INTR = 0x0200,
- NETIF_MSG_TX_DONE = 0x0400,
- NETIF_MSG_RX_STATUS = 0x0800,
- NETIF_MSG_PKTDATA = 0x1000,
- NETIF_MSG_HW = 0x2000,
- NETIF_MSG_WOL = 0x4000,
-};
-#endif
-
-#ifndef NETLINK_GENERIC
-#define NETLINK_GENERIC 16
-#endif
-
#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
static void exit_bad_args(void) __attribute__((noreturn));
@@ -88,6 +70,16 @@ static void exit_bad_args(void)
exit(1);
}
+static void exit_nlonly_param(const char *name) __attribute__((noreturn));
+
+static void exit_nlonly_param(const char *name)
+{
+ fprintf(stderr,
+ "ethtool: parameter '%s' can be used only with netlink\n",
+ name);
+ exit(1);
+}
+
typedef enum {
CMDL_NONE,
CMDL_BOOL,
@@ -119,74 +111,6 @@ struct cmdline_info {
void *seen_val;
};
-struct flag_info {
- const char *name;
- u32 value;
-};
-
-static const struct flag_info flags_msglvl[] = {
- { "drv", NETIF_MSG_DRV },
- { "probe", NETIF_MSG_PROBE },
- { "link", NETIF_MSG_LINK },
- { "timer", NETIF_MSG_TIMER },
- { "ifdown", NETIF_MSG_IFDOWN },
- { "ifup", NETIF_MSG_IFUP },
- { "rx_err", NETIF_MSG_RX_ERR },
- { "tx_err", NETIF_MSG_TX_ERR },
- { "tx_queued", NETIF_MSG_TX_QUEUED },
- { "intr", NETIF_MSG_INTR },
- { "tx_done", NETIF_MSG_TX_DONE },
- { "rx_status", NETIF_MSG_RX_STATUS },
- { "pktdata", NETIF_MSG_PKTDATA },
- { "hw", NETIF_MSG_HW },
- { "wol", NETIF_MSG_WOL },
-};
-
-struct off_flag_def {
- const char *short_name;
- const char *long_name;
- const char *kernel_name;
- u32 get_cmd, set_cmd;
- u32 value;
- /* For features exposed through ETHTOOL_GFLAGS, the oldest
- * kernel version for which we can trust the result. Where
- * the flag was added at the same time the kernel started
- * supporting the feature, this is 0 (to allow for backports).
- * Where the feature was supported before the flag was added,
- * it is the version that introduced the flag.
- */
- u32 min_kernel_ver;
-};
-static const struct off_flag_def off_flag_def[] = {
- { "rx", "rx-checksumming", "rx-checksum",
- ETHTOOL_GRXCSUM, ETHTOOL_SRXCSUM, ETH_FLAG_RXCSUM, 0 },
- { "tx", "tx-checksumming", "tx-checksum-*",
- ETHTOOL_GTXCSUM, ETHTOOL_STXCSUM, ETH_FLAG_TXCSUM, 0 },
- { "sg", "scatter-gather", "tx-scatter-gather*",
- ETHTOOL_GSG, ETHTOOL_SSG, ETH_FLAG_SG, 0 },
- { "tso", "tcp-segmentation-offload", "tx-tcp*-segmentation",
- ETHTOOL_GTSO, ETHTOOL_STSO, ETH_FLAG_TSO, 0 },
- { "ufo", "udp-fragmentation-offload", "tx-udp-fragmentation",
- ETHTOOL_GUFO, ETHTOOL_SUFO, ETH_FLAG_UFO, 0 },
- { "gso", "generic-segmentation-offload", "tx-generic-segmentation",
- ETHTOOL_GGSO, ETHTOOL_SGSO, ETH_FLAG_GSO, 0 },
- { "gro", "generic-receive-offload", "rx-gro",
- ETHTOOL_GGRO, ETHTOOL_SGRO, ETH_FLAG_GRO, 0 },
- { "lro", "large-receive-offload", "rx-lro",
- 0, 0, ETH_FLAG_LRO,
- KERNEL_VERSION(2,6,24) },
- { "rxvlan", "rx-vlan-offload", "rx-vlan-hw-parse",
- 0, 0, ETH_FLAG_RXVLAN,
- KERNEL_VERSION(2,6,37) },
- { "txvlan", "tx-vlan-offload", "tx-vlan-hw-insert",
- 0, 0, ETH_FLAG_TXVLAN,
- KERNEL_VERSION(2,6,37) },
- { "ntuple", "ntuple-filters", "rx-ntuple-filter",
- 0, 0, ETH_FLAG_NTUPLE, 0 },
- { "rxhash", "receive-hashing", "rx-hashing",
- 0, 0, ETH_FLAG_RXHASH, 0 },
-};
-
struct feature_def {
char name[ETH_GSTRING_LEN];
int off_flag_index; /* index in off_flag_def; negative if none match */
@@ -195,7 +119,7 @@ struct feature_def {
struct feature_defs {
size_t n_features;
/* Number of features each offload flag is associated with */
- unsigned int off_flag_matched[ARRAY_SIZE(off_flag_def)];
+ unsigned int off_flag_matched[OFF_FLAG_DEF_SIZE];
/* Name and offload flag index for each feature */
struct feature_def def[0];
};
@@ -307,9 +231,9 @@ static void parse_generic_cmdline(struct cmd_context *ctx,
struct cmdline_info *info,
unsigned int n_info)
{
- int argc = ctx->argc;
+ unsigned int argc = ctx->argc;
char **argp = ctx->argp;
- int i, idx;
+ unsigned int i, idx;
int found;
for (i = 0; i < argc; i++) {
@@ -375,7 +299,7 @@ static void parse_generic_cmdline(struct cmd_context *ctx,
case CMDL_IP4: {
u32 *p = info[idx].wanted_val;
struct in_addr in;
- if (!inet_aton(argp[i], &in))
+ if (!inet_pton(AF_INET, argp[i], &in))
exit_bad_args();
*p = in.s_addr;
break;
@@ -424,26 +348,6 @@ static void flag_to_cmdline_info(const char *name, u32 value,
cli->seen_val = mask;
}
-static void
-print_flags(const struct flag_info *info, unsigned int n_info, u32 value)
-{
- const char *sep = "";
-
- while (n_info) {
- if (value & info->value) {
- printf("%s%s", sep, info->name);
- sep = " ";
- value &= ~info->value;
- }
- ++info;
- --n_info;
- }
-
- /* Print any unrecognised flags in hex */
- if (value)
- printf("%s%#x", sep, value);
-}
-
static int rxflow_str_to_type(const char *str)
{
int flow_type = 0;
@@ -470,7 +374,7 @@ static int rxflow_str_to_type(const char *str)
return flow_type;
}
-static int do_version(struct cmd_context *ctx maybe_unused)
+static int do_version(struct cmd_context *ctx __maybe_unused)
{
fprintf(stdout,
PACKAGE " version " VERSION
@@ -496,9 +400,9 @@ static void init_global_link_mode_masks(void)
ETHTOOL_LINK_MODE_100baseT_Full_BIT,
ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
- ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
- ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
+ ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
+ ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
ETHTOOL_LINK_MODE_10000baseR_FEC_BIT,
@@ -547,6 +451,38 @@ static void init_global_link_mode_masks(void)
ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT,
ETHTOOL_LINK_MODE_100baseT1_Full_BIT,
ETHTOOL_LINK_MODE_1000baseT1_Full_BIT,
+ ETHTOOL_LINK_MODE_400000baseKR8_Full_BIT,
+ ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT,
+ ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT,
+ ETHTOOL_LINK_MODE_400000baseDR8_Full_BIT,
+ ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT,
+ ETHTOOL_LINK_MODE_100000baseKR_Full_BIT,
+ ETHTOOL_LINK_MODE_100000baseSR_Full_BIT,
+ ETHTOOL_LINK_MODE_100000baseLR_ER_FR_Full_BIT,
+ ETHTOOL_LINK_MODE_100000baseCR_Full_BIT,
+ ETHTOOL_LINK_MODE_100000baseDR_Full_BIT,
+ ETHTOOL_LINK_MODE_200000baseKR2_Full_BIT,
+ ETHTOOL_LINK_MODE_200000baseSR2_Full_BIT,
+ ETHTOOL_LINK_MODE_200000baseLR2_ER2_FR2_Full_BIT,
+ ETHTOOL_LINK_MODE_200000baseDR2_Full_BIT,
+ ETHTOOL_LINK_MODE_200000baseCR2_Full_BIT,
+ ETHTOOL_LINK_MODE_400000baseKR4_Full_BIT,
+ ETHTOOL_LINK_MODE_400000baseSR4_Full_BIT,
+ ETHTOOL_LINK_MODE_400000baseLR4_ER4_FR4_Full_BIT,
+ ETHTOOL_LINK_MODE_400000baseDR4_Full_BIT,
+ ETHTOOL_LINK_MODE_400000baseCR4_Full_BIT,
+ ETHTOOL_LINK_MODE_100baseFX_Half_BIT,
+ ETHTOOL_LINK_MODE_100baseFX_Full_BIT,
+ ETHTOOL_LINK_MODE_10baseT1L_Full_BIT,
+ ETHTOOL_LINK_MODE_800000baseCR8_Full_BIT,
+ ETHTOOL_LINK_MODE_800000baseKR8_Full_BIT,
+ ETHTOOL_LINK_MODE_800000baseDR8_Full_BIT,
+ ETHTOOL_LINK_MODE_800000baseDR8_2_Full_BIT,
+ ETHTOOL_LINK_MODE_800000baseSR8_Full_BIT,
+ ETHTOOL_LINK_MODE_800000baseVR8_Full_BIT,
+ ETHTOOL_LINK_MODE_10baseT1S_Full_BIT,
+ ETHTOOL_LINK_MODE_10baseT1S_Half_BIT,
+ ETHTOOL_LINK_MODE_10baseT1S_P2MP_Half_BIT,
};
static const enum ethtool_link_mode_bit_indices
additional_advertised_flags_bits[] = {
@@ -562,6 +498,7 @@ static void init_global_link_mode_masks(void)
ETHTOOL_LINK_MODE_FEC_NONE_BIT,
ETHTOOL_LINK_MODE_FEC_RS_BIT,
ETHTOOL_LINK_MODE_FEC_BASER_BIT,
+ ETHTOOL_LINK_MODE_FEC_LLRS_BIT,
};
unsigned int i;
@@ -636,20 +573,16 @@ static void dump_link_caps(const char *prefix, const char *an_prefix,
"100baseT/Half" },
{ 1, ETHTOOL_LINK_MODE_100baseT_Full_BIT,
"100baseT/Full" },
- { 0, ETHTOOL_LINK_MODE_100baseT1_Full_BIT,
- "100baseT1/Full" },
{ 0, ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
"1000baseT/Half" },
{ 1, ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
"1000baseT/Full" },
- { 0, ETHTOOL_LINK_MODE_1000baseT1_Full_BIT,
- "1000baseT1/Full" },
- { 0, ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
- "1000baseKX/Full" },
- { 0, ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
- "2500baseX/Full" },
{ 0, ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
"10000baseT/Full" },
+ { 0, ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
+ "2500baseX/Full" },
+ { 0, ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
+ "1000baseKX/Full" },
{ 0, ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
"10000baseKX4/Full" },
{ 0, ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
@@ -742,10 +675,79 @@ static void dump_link_caps(const char *prefix, const char *an_prefix,
"200000baseDR4/Full" },
{ 0, ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT,
"200000baseCR4/Full" },
+ { 0, ETHTOOL_LINK_MODE_100baseT1_Full_BIT,
+ "100baseT1/Full" },
+ { 0, ETHTOOL_LINK_MODE_1000baseT1_Full_BIT,
+ "1000baseT1/Full" },
+ { 0, ETHTOOL_LINK_MODE_400000baseKR8_Full_BIT,
+ "400000baseKR8/Full" },
+ { 0, ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT,
+ "400000baseSR8/Full" },
+ { 0, ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT,
+ "400000baseLR8_ER8_FR8/Full" },
+ { 0, ETHTOOL_LINK_MODE_400000baseDR8_Full_BIT,
+ "400000baseDR8/Full" },
+ { 0, ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT,
+ "400000baseCR8/Full" },
+ { 0, ETHTOOL_LINK_MODE_100000baseKR_Full_BIT,
+ "100000baseKR/Full" },
+ { 0, ETHTOOL_LINK_MODE_100000baseSR_Full_BIT,
+ "100000baseSR/Full" },
+ { 0, ETHTOOL_LINK_MODE_100000baseLR_ER_FR_Full_BIT,
+ "100000baseLR_ER_FR/Full" },
+ { 0, ETHTOOL_LINK_MODE_100000baseDR_Full_BIT,
+ "100000baseDR/Full" },
+ { 0, ETHTOOL_LINK_MODE_100000baseCR_Full_BIT,
+ "100000baseCR/Full" },
+ { 0, ETHTOOL_LINK_MODE_200000baseKR2_Full_BIT,
+ "200000baseKR2/Full" },
+ { 0, ETHTOOL_LINK_MODE_200000baseSR2_Full_BIT,
+ "200000baseSR2/Full" },
+ { 0, ETHTOOL_LINK_MODE_200000baseLR2_ER2_FR2_Full_BIT,
+ "200000baseLR2_ER2_FR2/Full" },
+ { 0, ETHTOOL_LINK_MODE_200000baseDR2_Full_BIT,
+ "200000baseDR2/Full" },
+ { 0, ETHTOOL_LINK_MODE_200000baseCR2_Full_BIT,
+ "200000baseCR2/Full" },
+ { 0, ETHTOOL_LINK_MODE_400000baseKR4_Full_BIT,
+ "400000baseKR4/Full" },
+ { 0, ETHTOOL_LINK_MODE_400000baseSR4_Full_BIT,
+ "400000baseSR4/Full" },
+ { 0, ETHTOOL_LINK_MODE_400000baseLR4_ER4_FR4_Full_BIT,
+ "400000baseLR4_ER4_FR4/Full" },
+ { 0, ETHTOOL_LINK_MODE_400000baseDR4_Full_BIT,
+ "400000baseDR4/Full" },
+ { 0, ETHTOOL_LINK_MODE_400000baseCR4_Full_BIT,
+ "400000baseCR4/Full" },
+ { 0, ETHTOOL_LINK_MODE_100baseFX_Half_BIT,
+ "100baseFX/Half" },
+ { 1, ETHTOOL_LINK_MODE_100baseFX_Full_BIT,
+ "100baseFX/Full" },
+ { 0, ETHTOOL_LINK_MODE_10baseT1L_Full_BIT,
+ "10baseT1L/Full" },
+ { 0, ETHTOOL_LINK_MODE_800000baseCR8_Full_BIT,
+ "800000baseCR8/Full" },
+ { 0, ETHTOOL_LINK_MODE_800000baseKR8_Full_BIT,
+ "800000baseKR8/Full" },
+ { 0, ETHTOOL_LINK_MODE_800000baseDR8_Full_BIT,
+ "800000baseDR8/Full" },
+ { 0, ETHTOOL_LINK_MODE_800000baseDR8_2_Full_BIT,
+ "800000baseDR8_2/Full" },
+ { 0, ETHTOOL_LINK_MODE_800000baseSR8_Full_BIT,
+ "800000baseSR8/Full" },
+ { 0, ETHTOOL_LINK_MODE_800000baseVR8_Full_BIT,
+ "800000baseVR8/Full" },
+ { 0, ETHTOOL_LINK_MODE_10baseT1S_Full_BIT,
+ "10baseT1S/Full" },
+ { 1, ETHTOOL_LINK_MODE_10baseT1S_Half_BIT,
+ "10baseT1S/Half" },
+ { 0, ETHTOOL_LINK_MODE_10baseT1S_P2MP_Half_BIT,
+ "10baseT1S/Half" },
};
int indent;
- int did1, new_line_pend, i;
+ int did1, new_line_pend;
int fecreported = 0;
+ unsigned int i;
/* Indent just like the separate functions used to */
indent = strlen(prefix) + 14;
@@ -814,6 +816,12 @@ static void dump_link_caps(const char *prefix, const char *an_prefix,
fprintf(stdout, " RS");
fecreported = 1;
}
+ if (ethtool_link_mode_test_bit(ETHTOOL_LINK_MODE_FEC_LLRS_BIT,
+ mask)) {
+ fprintf(stdout, " LLRS");
+ fecreported = 1;
+ }
+
if (!fecreported)
fprintf(stdout, " Not reported");
fprintf(stdout, "\n");
@@ -902,31 +910,9 @@ dump_link_usettings(const struct ethtool_link_usettings *link_usettings)
(link_usettings->base.autoneg == AUTONEG_DISABLE) ?
"off" : "on");
- if (link_usettings->base.port == PORT_TP) {
- fprintf(stdout, " MDI-X: ");
- if (link_usettings->base.eth_tp_mdix_ctrl == ETH_TP_MDI) {
- fprintf(stdout, "off (forced)\n");
- } else if (link_usettings->base.eth_tp_mdix_ctrl
- == ETH_TP_MDI_X) {
- fprintf(stdout, "on (forced)\n");
- } else {
- switch (link_usettings->base.eth_tp_mdix) {
- case ETH_TP_MDI:
- fprintf(stdout, "off");
- break;
- case ETH_TP_MDI_X:
- fprintf(stdout, "on");
- break;
- default:
- fprintf(stdout, "Unknown");
- break;
- }
- if (link_usettings->base.eth_tp_mdix_ctrl
- == ETH_TP_MDI_AUTO)
- fprintf(stdout, " (auto)");
- fprintf(stdout, "\n");
- }
- }
+ if (link_usettings->base.port == PORT_TP)
+ dump_mdix(link_usettings->base.eth_tp_mdix,
+ link_usettings->base.eth_tp_mdix_ctrl);
return 0;
}
@@ -998,58 +984,6 @@ static int parse_wolopts(char *optstr, u32 *data)
return 0;
}
-static char *unparse_wolopts(int wolopts)
-{
- static char buf[16];
- char *p = buf;
-
- memset(buf, 0, sizeof(buf));
-
- if (wolopts) {
- if (wolopts & WAKE_PHY)
- *p++ = 'p';
- if (wolopts & WAKE_UCAST)
- *p++ = 'u';
- if (wolopts & WAKE_MCAST)
- *p++ = 'm';
- if (wolopts & WAKE_BCAST)
- *p++ = 'b';
- if (wolopts & WAKE_ARP)
- *p++ = 'a';
- if (wolopts & WAKE_MAGIC)
- *p++ = 'g';
- if (wolopts & WAKE_MAGICSECURE)
- *p++ = 's';
- if (wolopts & WAKE_FILTER)
- *p++ = 'f';
- } else {
- *p = 'd';
- }
-
- return buf;
-}
-
-static 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));
- if (wol->supported & WAKE_MAGICSECURE) {
- int i;
- int delim = 0;
-
- fprintf(stdout, " SecureOn password: ");
- for (i = 0; i < SOPASS_MAX; i++) {
- fprintf(stdout, "%s%02x", delim?":":"", wol->sopass[i]);
- delim = 1;
- }
- fprintf(stdout, "\n");
- }
-
- return 0;
-}
-
static int parse_rxfhashopts(char *optstr, u32 *data)
{
*data = 0;
@@ -1183,12 +1117,12 @@ static int parse_hkey(char **rss_hkey, u32 key_size,
return 0;
}
+#ifdef ETHTOOL_ENABLE_PRETTY_DUMP
static const struct {
const char *name;
int (*func)(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
} driver_list[] = {
-#ifdef ETHTOOL_ENABLE_PRETTY_DUMP
{ "8139cp", realtek_dump_regs },
{ "8139too", realtek_dump_regs },
{ "r8169", realtek_dump_regs },
@@ -1221,8 +1155,15 @@ static const struct {
{ "lan78xx", lan78xx_dump_regs },
{ "dsa", dsa_dump_regs },
{ "fec", fec_dump_regs },
-#endif
+ { "igc", igc_dump_regs },
+ { "bnxt_en", bnxt_dump_regs },
+ { "cpsw-switch", cpsw_dump_regs },
+ { "lan743x", lan743x_dump_regs },
+ { "fsl_enetc", fsl_enetc_dump_regs },
+ { "fsl_enetc_vf", fsl_enetc_dump_regs },
+ { "hns3", hns3_dump_regs },
};
+#endif
void dump_hex(FILE *file, const u8 *data, int len, int offset)
{
@@ -1241,14 +1182,15 @@ void dump_hex(FILE *file, const u8 *data, int len, int offset)
static int dump_regs(int gregs_dump_raw, int gregs_dump_hex,
struct ethtool_drvinfo *info, struct ethtool_regs *regs)
{
- int i;
-
if (gregs_dump_raw) {
fwrite(regs->data, regs->len, 1, stdout);
goto nested;
}
- if (!gregs_dump_hex)
+#ifdef ETHTOOL_ENABLE_PRETTY_DUMP
+ if (!gregs_dump_hex) {
+ unsigned int i;
+
for (i = 0; i < ARRAY_SIZE(driver_list); i++)
if (!strncmp(driver_list[i].name, info->driver,
ETHTOOL_BUSINFO_LEN)) {
@@ -1260,6 +1202,8 @@ static int dump_regs(int gregs_dump_raw, int gregs_dump_hex,
*/
break;
}
+ }
+#endif
dump_hex(stdout, regs->data, regs->len, 0);
@@ -1276,7 +1220,7 @@ nested:
}
static int dump_eeprom(int geeprom_dump_raw,
- struct ethtool_drvinfo *info maybe_unused,
+ struct ethtool_drvinfo *info __maybe_unused,
struct ethtool_eeprom *ee)
{
if (geeprom_dump_raw) {
@@ -1298,7 +1242,8 @@ static int dump_eeprom(int geeprom_dump_raw,
static int dump_test(struct ethtool_test *test,
struct ethtool_gstrings *strings)
{
- int i, rc;
+ unsigned int i;
+ int rc;
rc = test->flags & ETH_TEST_FL_FAILED;
fprintf(stdout, "The test result is %s\n", rc ? "FAIL" : "PASS");
@@ -1529,7 +1474,7 @@ static void dump_one_feature(const char *indent, const char *name,
: "");
}
-static int linux_version_code(void)
+static unsigned int linux_version_code(void)
{
struct utsname utsname;
unsigned version, patchlevel, sublevel = 0;
@@ -1545,12 +1490,12 @@ static void dump_features(const struct feature_defs *defs,
const struct feature_state *state,
const struct feature_state *ref_state)
{
- int kernel_ver = linux_version_code();
- u32 value;
+ unsigned int kernel_ver = linux_version_code();
+ unsigned int i, j;
int indent;
- int i, j;
+ u32 value;
- for (i = 0; i < ARRAY_SIZE(off_flag_def); i++) {
+ for (i = 0; i < OFF_FLAG_DEF_SIZE; i++) {
/* Don't show features whose state is unknown on this
* kernel version
*/
@@ -1581,7 +1526,7 @@ static void dump_features(const struct feature_defs *defs,
/* Show matching features */
for (j = 0; j < defs->n_features; j++) {
- if (defs->def[j].off_flag_index != i)
+ if (defs->def[j].off_flag_index != (int)i)
continue;
if (defs->off_flag_matched[i] != 1)
/* Show all matching feature states */
@@ -1696,6 +1641,8 @@ static void dump_fec(u32 fec)
fprintf(stdout, " BaseR");
if (fec & ETHTOOL_FEC_RS)
fprintf(stdout, " RS");
+ if (fec & ETHTOOL_FEC_LLRS)
+ fprintf(stdout, " LLRS");
}
#define N_SOTS 7
@@ -1800,7 +1747,9 @@ get_stringset(struct cmd_context *ctx, enum ethtool_stringset set_id,
sset_info.hdr.reserved = 0;
sset_info.hdr.sset_mask = 1ULL << set_id;
if (send_ioctl(ctx, &sset_info) == 0) {
- len = sset_info.hdr.sset_mask ? sset_info.hdr.data[0] : 0;
+ const u32 *sset_lengths = sset_info.hdr.data;
+
+ len = sset_info.hdr.sset_mask ? sset_lengths[0] : 0;
} else if (errno == EOPNOTSUPP && drvinfo_offset != 0) {
/* Fallback for old kernel versions */
drvinfo.cmd = ETHTOOL_GDRVINFO;
@@ -1834,8 +1783,8 @@ static struct feature_defs *get_feature_defs(struct cmd_context *ctx)
{
struct ethtool_gstrings *names;
struct feature_defs *defs;
+ unsigned int i, j;
u32 n_features;
- int i, j;
names = get_stringset(ctx, ETH_SS_FEATURES, 0, 1);
if (names) {
@@ -1867,7 +1816,7 @@ static struct feature_defs *get_feature_defs(struct cmd_context *ctx)
defs->def[i].off_flag_index = -1;
for (j = 0;
- j < ARRAY_SIZE(off_flag_def) &&
+ j < OFF_FLAG_DEF_SIZE &&
defs->def[i].off_flag_index < 0;
j++) {
const char *pattern =
@@ -1989,10 +1938,24 @@ static int do_spause(struct cmd_context *ctx)
int pause_rx_wanted = -1;
int pause_tx_wanted = -1;
struct cmdline_info cmdline_pause[] = {
- { "autoneg", CMDL_BOOL, &pause_autoneg_wanted,
- &epause.autoneg },
- { "rx", CMDL_BOOL, &pause_rx_wanted, &epause.rx_pause },
- { "tx", CMDL_BOOL, &pause_tx_wanted, &epause.tx_pause },
+ {
+ .name = "autoneg",
+ .type = CMDL_BOOL,
+ .wanted_val = &pause_autoneg_wanted,
+ .ioctl_val = &epause.autoneg,
+ },
+ {
+ .name = "rx",
+ .type = CMDL_BOOL,
+ .wanted_val = &pause_rx_wanted,
+ .ioctl_val = &epause.rx_pause,
+ },
+ {
+ .name = "tx",
+ .type = CMDL_BOOL,
+ .wanted_val = &pause_tx_wanted,
+ .ioctl_val = &epause.tx_pause,
+ },
};
int err, changed = 0;
@@ -2032,12 +1995,30 @@ static int do_sring(struct cmd_context *ctx)
s32 ring_rx_jumbo_wanted = -1;
s32 ring_tx_wanted = -1;
struct cmdline_info cmdline_ring[] = {
- { "rx", CMDL_S32, &ring_rx_wanted, &ering.rx_pending },
- { "rx-mini", CMDL_S32, &ring_rx_mini_wanted,
- &ering.rx_mini_pending },
- { "rx-jumbo", CMDL_S32, &ring_rx_jumbo_wanted,
- &ering.rx_jumbo_pending },
- { "tx", CMDL_S32, &ring_tx_wanted, &ering.tx_pending },
+ {
+ .name = "rx",
+ .type = CMDL_S32,
+ .wanted_val = &ring_rx_wanted,
+ .ioctl_val = &ering.rx_pending,
+ },
+ {
+ .name = "rx-mini",
+ .type = CMDL_S32,
+ .wanted_val = &ring_rx_mini_wanted,
+ .ioctl_val = &ering.rx_mini_pending,
+ },
+ {
+ .name = "rx-jumbo",
+ .type = CMDL_S32,
+ .wanted_val = &ring_rx_jumbo_wanted,
+ .ioctl_val = &ering.rx_jumbo_pending,
+ },
+ {
+ .name = "tx",
+ .type = CMDL_S32,
+ .wanted_val = &ring_tx_wanted,
+ .ioctl_val = &ering.tx_pending,
+ },
};
int err, changed = 0;
@@ -2101,12 +2082,30 @@ static int do_schannels(struct cmd_context *ctx)
s32 channels_other_wanted = -1;
s32 channels_combined_wanted = -1;
struct cmdline_info cmdline_channels[] = {
- { "rx", CMDL_S32, &channels_rx_wanted, &echannels.rx_count },
- { "tx", CMDL_S32, &channels_tx_wanted, &echannels.tx_count },
- { "other", CMDL_S32, &channels_other_wanted,
- &echannels.other_count },
- { "combined", CMDL_S32, &channels_combined_wanted,
- &echannels.combined_count },
+ {
+ .name = "rx",
+ .type = CMDL_S32,
+ .wanted_val = &channels_rx_wanted,
+ .ioctl_val = &echannels.rx_count,
+ },
+ {
+ .name = "tx",
+ .type = CMDL_S32,
+ .wanted_val = &channels_tx_wanted,
+ .ioctl_val = &echannels.tx_count,
+ },
+ {
+ .name = "other",
+ .type = CMDL_S32,
+ .wanted_val = &channels_other_wanted,
+ .ioctl_val = &echannels.other_count,
+ },
+ {
+ .name = "combined",
+ .type = CMDL_S32,
+ .wanted_val = &channels_combined_wanted,
+ .ioctl_val = &echannels.combined_count,
+ },
};
int err, changed = 0;
@@ -2159,7 +2158,7 @@ static int do_gchannels(struct cmd_context *ctx)
if (err)
return err;
} else {
- perror("Cannot get device channel parameters\n");
+ perror("Cannot get device channel parameters");
return 1;
}
return 0;
@@ -2216,50 +2215,138 @@ static int do_gcoalesce(struct cmd_context *ctx)
#define COALESCE_CMDLINE_INFO(__ecoal) \
{ \
- { "adaptive-rx", CMDL_BOOL, &coal_adaptive_rx_wanted, \
- &__ecoal.use_adaptive_rx_coalesce }, \
- { "adaptive-tx", CMDL_BOOL, &coal_adaptive_tx_wanted, \
- &__ecoal.use_adaptive_tx_coalesce }, \
- { "sample-interval", CMDL_S32, &coal_sample_rate_wanted, \
- &__ecoal.rate_sample_interval }, \
- { "stats-block-usecs", CMDL_S32, &coal_stats_wanted, \
- &__ecoal.stats_block_coalesce_usecs }, \
- { "pkt-rate-low", CMDL_S32, &coal_pkt_rate_low_wanted, \
- &__ecoal.pkt_rate_low }, \
- { "pkt-rate-high", CMDL_S32, &coal_pkt_rate_high_wanted, \
- &__ecoal.pkt_rate_high }, \
- { "rx-usecs", CMDL_S32, &coal_rx_usec_wanted, \
- &__ecoal.rx_coalesce_usecs }, \
- { "rx-frames", CMDL_S32, &coal_rx_frames_wanted, \
- &__ecoal.rx_max_coalesced_frames }, \
- { "rx-usecs-irq", CMDL_S32, &coal_rx_usec_irq_wanted, \
- &__ecoal.rx_coalesce_usecs_irq }, \
- { "rx-frames-irq", CMDL_S32, &coal_rx_frames_irq_wanted, \
- &__ecoal.rx_max_coalesced_frames_irq }, \
- { "tx-usecs", CMDL_S32, &coal_tx_usec_wanted, \
- &__ecoal.tx_coalesce_usecs }, \
- { "tx-frames", CMDL_S32, &coal_tx_frames_wanted, \
- &__ecoal.tx_max_coalesced_frames }, \
- { "tx-usecs-irq", CMDL_S32, &coal_tx_usec_irq_wanted, \
- &__ecoal.tx_coalesce_usecs_irq }, \
- { "tx-frames-irq", CMDL_S32, &coal_tx_frames_irq_wanted, \
- &__ecoal.tx_max_coalesced_frames_irq }, \
- { "rx-usecs-low", CMDL_S32, &coal_rx_usec_low_wanted, \
- &__ecoal.rx_coalesce_usecs_low }, \
- { "rx-frames-low", CMDL_S32, &coal_rx_frames_low_wanted, \
- &__ecoal.rx_max_coalesced_frames_low }, \
- { "tx-usecs-low", CMDL_S32, &coal_tx_usec_low_wanted, \
- &__ecoal.tx_coalesce_usecs_low }, \
- { "tx-frames-low", CMDL_S32, &coal_tx_frames_low_wanted, \
- &__ecoal.tx_max_coalesced_frames_low }, \
- { "rx-usecs-high", CMDL_S32, &coal_rx_usec_high_wanted, \
- &__ecoal.rx_coalesce_usecs_high }, \
- { "rx-frames-high", CMDL_S32, &coal_rx_frames_high_wanted, \
- &__ecoal.rx_max_coalesced_frames_high }, \
- { "tx-usecs-high", CMDL_S32, &coal_tx_usec_high_wanted, \
- &__ecoal.tx_coalesce_usecs_high }, \
- { "tx-frames-high", CMDL_S32, &coal_tx_frames_high_wanted, \
- &__ecoal.tx_max_coalesced_frames_high }, \
+ { \
+ .name = "adaptive-rx", \
+ .type = CMDL_BOOL, \
+ .wanted_val = &coal_adaptive_rx_wanted, \
+ .ioctl_val = &__ecoal.use_adaptive_rx_coalesce, \
+ }, \
+ { \
+ .name = "adaptive-tx", \
+ .type = CMDL_BOOL, \
+ .wanted_val = &coal_adaptive_tx_wanted, \
+ .ioctl_val = &__ecoal.use_adaptive_tx_coalesce, \
+ }, \
+ { \
+ .name = "sample-interval", \
+ .type = CMDL_S32, \
+ .wanted_val = &coal_sample_rate_wanted, \
+ .ioctl_val = &__ecoal.rate_sample_interval, \
+ }, \
+ { \
+ .name = "stats-block-usecs", \
+ .type = CMDL_S32, \
+ .wanted_val = &coal_stats_wanted, \
+ .ioctl_val = &__ecoal.stats_block_coalesce_usecs, \
+ }, \
+ { \
+ .name = "pkt-rate-low", \
+ .type = CMDL_S32, \
+ .wanted_val = &coal_pkt_rate_low_wanted, \
+ .ioctl_val = &__ecoal.pkt_rate_low, \
+ }, \
+ { \
+ .name = "pkt-rate-high", \
+ .type = CMDL_S32, \
+ .wanted_val = &coal_pkt_rate_high_wanted, \
+ .ioctl_val = &__ecoal.pkt_rate_high, \
+ }, \
+ { \
+ .name = "rx-usecs", \
+ .type = CMDL_S32, \
+ .wanted_val = &coal_rx_usec_wanted, \
+ .ioctl_val = &__ecoal.rx_coalesce_usecs, \
+ }, \
+ { \
+ .name = "rx-frames", \
+ .type = CMDL_S32, \
+ .wanted_val = &coal_rx_frames_wanted, \
+ .ioctl_val = &__ecoal.rx_max_coalesced_frames, \
+ }, \
+ { \
+ .name = "rx-usecs-irq", \
+ .type = CMDL_S32, \
+ .wanted_val = &coal_rx_usec_irq_wanted, \
+ .ioctl_val = &__ecoal.rx_coalesce_usecs_irq, \
+ }, \
+ { \
+ .name = "rx-frames-irq", \
+ .type = CMDL_S32, \
+ .wanted_val = &coal_rx_frames_irq_wanted, \
+ .ioctl_val = &__ecoal.rx_max_coalesced_frames_irq, \
+ }, \
+ { \
+ .name = "tx-usecs", \
+ .type = CMDL_S32, \
+ .wanted_val = &coal_tx_usec_wanted, \
+ .ioctl_val = &__ecoal.tx_coalesce_usecs, \
+ }, \
+ { \
+ .name = "tx-frames", \
+ .type = CMDL_S32, \
+ .wanted_val = &coal_tx_frames_wanted, \
+ .ioctl_val = &__ecoal.tx_max_coalesced_frames, \
+ }, \
+ { \
+ .name = "tx-usecs-irq", \
+ .type = CMDL_S32, \
+ .wanted_val = &coal_tx_usec_irq_wanted, \
+ .ioctl_val = &__ecoal.tx_coalesce_usecs_irq, \
+ }, \
+ { \
+ .name = "tx-frames-irq", \
+ .type = CMDL_S32, \
+ .wanted_val = &coal_tx_frames_irq_wanted, \
+ .ioctl_val = &__ecoal.tx_max_coalesced_frames_irq, \
+ }, \
+ { \
+ .name = "rx-usecs-low", \
+ .type = CMDL_S32, \
+ .wanted_val = &coal_rx_usec_low_wanted, \
+ .ioctl_val = &__ecoal.rx_coalesce_usecs_low, \
+ }, \
+ { \
+ .name = "rx-frames-low", \
+ .type = CMDL_S32, \
+ .wanted_val = &coal_rx_frames_low_wanted, \
+ .ioctl_val = &__ecoal.rx_max_coalesced_frames_low, \
+ }, \
+ { \
+ .name = "tx-usecs-low", \
+ .type = CMDL_S32, \
+ .wanted_val = &coal_tx_usec_low_wanted, \
+ .ioctl_val = &__ecoal.tx_coalesce_usecs_low, \
+ }, \
+ { \
+ .name = "tx-frames-low", \
+ .type = CMDL_S32, \
+ .wanted_val = &coal_tx_frames_low_wanted, \
+ .ioctl_val = &__ecoal.tx_max_coalesced_frames_low, \
+ }, \
+ { \
+ .name = "rx-usecs-high", \
+ .type = CMDL_S32, \
+ .wanted_val = &coal_rx_usec_high_wanted, \
+ .ioctl_val = &__ecoal.rx_coalesce_usecs_high, \
+ }, \
+ { \
+ .name = "rx-frames-high", \
+ .type = CMDL_S32, \
+ .wanted_val = &coal_rx_frames_high_wanted, \
+ .ioctl_val = &__ecoal.rx_max_coalesced_frames_high,\
+ }, \
+ { \
+ .name = "tx-usecs-high", \
+ .type = CMDL_S32, \
+ .wanted_val = &coal_tx_usec_high_wanted, \
+ .ioctl_val = &__ecoal.tx_coalesce_usecs_high, \
+ }, \
+ { \
+ .name = "tx-frames-high", \
+ .type = CMDL_S32, \
+ .wanted_val = &coal_tx_frames_high_wanted, \
+ .ioctl_val = &__ecoal.tx_max_coalesced_frames_high,\
+ }, \
}
static int do_scoalesce(struct cmd_context *ctx)
@@ -2315,7 +2402,7 @@ get_features(struct cmd_context *ctx, const struct feature_defs *defs)
state->off_flags = 0;
- for (i = 0; i < ARRAY_SIZE(off_flag_def); i++) {
+ for (i = 0; i < OFF_FLAG_DEF_SIZE; i++) {
value = off_flag_def[i].value;
if (!off_flag_def[i].get_cmd)
continue;
@@ -2398,12 +2485,13 @@ static int do_sfeatures(struct cmd_context *ctx)
int any_changed = 0, any_mismatch = 0;
u32 off_flags_wanted = 0;
u32 off_flags_mask = 0;
- struct ethtool_sfeatures *efeatures;
+ struct ethtool_sfeatures *efeatures = NULL;
+ struct feature_state *old_state = NULL;
+ struct feature_state *new_state = NULL;
struct cmdline_info *cmdline_features;
- struct feature_state *old_state, *new_state;
struct ethtool_value eval;
+ unsigned int i, j;
int err, rc;
- int i, j;
defs = get_feature_defs(ctx);
if (!defs) {
@@ -2424,33 +2512,37 @@ static int do_sfeatures(struct cmd_context *ctx)
memset(efeatures->features, 0,
FEATURE_BITS_TO_BLOCKS(defs->n_features) *
sizeof(efeatures->features[0]));
- } else {
- efeatures = NULL;
}
/* Generate cmdline_info for legacy flags and kernel-named
* features, and parse our arguments.
*/
- cmdline_features = calloc(ARRAY_SIZE(off_flag_def) + defs->n_features,
+ cmdline_features = calloc(2 * OFF_FLAG_DEF_SIZE + defs->n_features,
sizeof(cmdline_features[0]));
if (!cmdline_features) {
perror("Cannot parse arguments");
rc = 1;
goto err;
}
- for (i = 0; i < ARRAY_SIZE(off_flag_def); i++)
+ j = 0;
+ for (i = 0; i < OFF_FLAG_DEF_SIZE; i++) {
flag_to_cmdline_info(off_flag_def[i].short_name,
off_flag_def[i].value,
&off_flags_wanted, &off_flags_mask,
- &cmdline_features[i]);
+ &cmdline_features[j++]);
+ flag_to_cmdline_info(off_flag_def[i].long_name,
+ off_flag_def[i].value,
+ &off_flags_wanted, &off_flags_mask,
+ &cmdline_features[j++]);
+ }
for (i = 0; i < defs->n_features; i++)
flag_to_cmdline_info(
defs->def[i].name, FEATURE_FIELD_FLAG(i),
&FEATURE_WORD(efeatures->features, i, requested),
&FEATURE_WORD(efeatures->features, i, valid),
- &cmdline_features[ARRAY_SIZE(off_flag_def) + i]);
+ &cmdline_features[j++]);
parse_generic_cmdline(ctx, &any_changed, cmdline_features,
- ARRAY_SIZE(off_flag_def) + defs->n_features);
+ 2 * OFF_FLAG_DEF_SIZE + defs->n_features);
free(cmdline_features);
if (!any_changed) {
@@ -2470,14 +2562,14 @@ static int do_sfeatures(struct cmd_context *ctx)
* related features that the user did not specify and that
* are not fixed. Warn if all related features are fixed.
*/
- for (i = 0; i < ARRAY_SIZE(off_flag_def); i++) {
+ for (i = 0; i < OFF_FLAG_DEF_SIZE; i++) {
int fixed = 1;
if (!(off_flags_mask & off_flag_def[i].value))
continue;
for (j = 0; j < defs->n_features; j++) {
- if (defs->def[j].off_flag_index != i ||
+ if (defs->def[j].off_flag_index != (int)i ||
!FEATURE_BIT_IS_SET(
old_state->features.features,
j, available) ||
@@ -2511,7 +2603,7 @@ static int do_sfeatures(struct cmd_context *ctx)
goto err;
}
} else {
- for (i = 0; i < ARRAY_SIZE(off_flag_def); i++) {
+ for (i = 0; i < OFF_FLAG_DEF_SIZE; i++) {
if (!off_flag_def[i].set_cmd)
continue;
if (off_flags_mask & off_flag_def[i].value) {
@@ -2578,9 +2670,11 @@ static int do_sfeatures(struct cmd_context *ctx)
rc = 0;
err:
+ free(new_state);
+ free(old_state);
free(defs);
- if (efeatures)
- free(efeatures);
+ free(efeatures);
+
return rc;
}
@@ -2631,8 +2725,8 @@ do_ioctl_glinksettings(struct cmd_context *ctx)
if (link_usettings == NULL)
return NULL;
- /* keep transceiver 0 */
memcpy(&link_usettings->base, &ecmd.req, sizeof(link_usettings->base));
+ link_usettings->deprecated.transceiver = ecmd.req.transceiver;
/* copy link mode bitmaps */
u32_offs = 0;
@@ -2837,8 +2931,7 @@ static int do_gset(struct cmd_context *ctx)
fprintf(stdout, " Current message level: 0x%08x (%d)\n"
" ",
edata.data, edata.data);
- print_flags(flags_msglvl, ARRAY_SIZE(flags_msglvl),
- edata.data);
+ print_flags(flags_msglvl, n_flags_msglvl, edata.data);
fprintf(stdout, "\n");
allfail = 0;
} else if (errno != EOPNOTSUPP) {
@@ -2884,13 +2977,13 @@ static int do_sset(struct cmd_context *ctx)
int msglvl_changed = 0;
u32 msglvl_wanted = 0;
u32 msglvl_mask = 0;
- struct cmdline_info cmdline_msglvl[ARRAY_SIZE(flags_msglvl)];
- int argc = ctx->argc;
+ struct cmdline_info cmdline_msglvl[n_flags_msglvl];
+ unsigned int argc = ctx->argc;
char **argp = ctx->argp;
- int i;
+ unsigned int i;
int err = 0;
- for (i = 0; i < ARRAY_SIZE(flags_msglvl); i++)
+ for (i = 0; i < n_flags_msglvl; i++)
flag_to_cmdline_info(flags_msglvl[i].name,
flags_msglvl[i].value,
&msglvl_wanted, &msglvl_mask,
@@ -3019,6 +3112,8 @@ static int do_sset(struct cmd_context *ctx)
ARRAY_SIZE(cmdline_msglvl));
break;
}
+ } else if (!strcmp(argp[i], "master-slave")) {
+ exit_nlonly_param(argp[i]);
} else {
exit_bad_args();
}
@@ -3071,6 +3166,9 @@ static int do_sset(struct cmd_context *ctx)
link_usettings = do_ioctl_glinksettings(ctx);
if (link_usettings == NULL)
link_usettings = do_ioctl_gset(ctx);
+ else
+ memset(&link_usettings->deprecated, 0,
+ sizeof(link_usettings->deprecated));
if (link_usettings == NULL) {
perror("Cannot get current device settings");
err = -1;
@@ -3247,9 +3345,21 @@ static int do_gregs(struct cmd_context *ctx)
int gregs_dump_hex = 0;
char *gregs_dump_file = NULL;
struct cmdline_info cmdline_gregs[] = {
- { "raw", CMDL_BOOL, &gregs_dump_raw, NULL },
- { "hex", CMDL_BOOL, &gregs_dump_hex, NULL },
- { "file", CMDL_STR, &gregs_dump_file, NULL },
+ {
+ .name = "raw",
+ .type = CMDL_BOOL,
+ .wanted_val = &gregs_dump_raw,
+ },
+ {
+ .name = "hex",
+ .type = CMDL_BOOL,
+ .wanted_val = &gregs_dump_hex,
+ },
+ {
+ .name = "file",
+ .type = CMDL_STR,
+ .wanted_val = &gregs_dump_file,
+ },
};
int err;
struct ethtool_drvinfo drvinfo;
@@ -3343,11 +3453,25 @@ static int do_geeprom(struct cmd_context *ctx)
int geeprom_changed = 0;
int geeprom_dump_raw = 0;
u32 geeprom_offset = 0;
- u32 geeprom_length = -1;
+ u32 geeprom_length = 0;
+ int geeprom_length_seen = 0;
struct cmdline_info cmdline_geeprom[] = {
- { "offset", CMDL_U32, &geeprom_offset, NULL },
- { "length", CMDL_U32, &geeprom_length, NULL },
- { "raw", CMDL_BOOL, &geeprom_dump_raw, NULL },
+ {
+ .name = "offset",
+ .type = CMDL_U32,
+ .wanted_val = &geeprom_offset,
+ },
+ {
+ .name = "length",
+ .type = CMDL_U32,
+ .wanted_val = &geeprom_length,
+ .seen_val = &geeprom_length_seen,
+ },
+ {
+ .name = "raw",
+ .type = CMDL_BOOL,
+ .wanted_val = &geeprom_dump_raw,
+ },
};
int err;
struct ethtool_drvinfo drvinfo;
@@ -3363,7 +3487,7 @@ static int do_geeprom(struct cmd_context *ctx)
return 74;
}
- if (geeprom_length == -1)
+ if (!geeprom_length_seen)
geeprom_length = drvinfo.eedump_len;
if (drvinfo.eedump_len < geeprom_offset + geeprom_length)
@@ -3393,16 +3517,34 @@ static int do_seeprom(struct cmd_context *ctx)
{
int seeprom_changed = 0;
u32 seeprom_magic = 0;
- u32 seeprom_length = -1;
+ u32 seeprom_length = 0;
u32 seeprom_offset = 0;
u8 seeprom_value = 0;
+ int seeprom_length_seen = 0;
int seeprom_value_seen = 0;
struct cmdline_info cmdline_seeprom[] = {
- { "magic", CMDL_U32, &seeprom_magic, NULL },
- { "offset", CMDL_U32, &seeprom_offset, NULL },
- { "length", CMDL_U32, &seeprom_length, NULL },
- { "value", CMDL_U8, &seeprom_value, NULL,
- 0, &seeprom_value_seen },
+ {
+ .name = "magic",
+ .type = CMDL_U32,
+ .wanted_val = &seeprom_magic,
+ },
+ {
+ .name = "offset",
+ .type = CMDL_U32,
+ .wanted_val = &seeprom_offset,
+ },
+ {
+ .name = "length",
+ .type = CMDL_U32,
+ .wanted_val = &seeprom_length,
+ .seen_val = &seeprom_length_seen,
+ },
+ {
+ .name = "value",
+ .type = CMDL_U8,
+ .wanted_val = &seeprom_value,
+ .seen_val = &seeprom_value_seen,
+ },
};
int err;
struct ethtool_drvinfo drvinfo;
@@ -3418,12 +3560,16 @@ static int do_seeprom(struct cmd_context *ctx)
return 74;
}
- if (seeprom_value_seen)
+ if (seeprom_value_seen && !seeprom_length_seen)
seeprom_length = 1;
-
- if (seeprom_length == -1)
+ else if (!seeprom_length_seen)
seeprom_length = drvinfo.eedump_len;
+ if (seeprom_value_seen && (seeprom_length != 1)) {
+ fprintf(stderr, "value requires length 1\n");
+ return 1;
+ }
+
if (drvinfo.eedump_len < seeprom_offset + seeprom_length) {
fprintf(stderr, "offset & length out of bounds\n");
return 1;
@@ -3760,27 +3906,6 @@ static int do_grxclass(struct cmd_context *ctx)
return err ? 1 : 0;
}
-static void print_indir_table(struct cmd_context *ctx,
- struct ethtool_rxnfc *ring_count,
- u32 indir_size, u32 *indir)
-{
- u32 i;
-
- printf("RX flow hash indirection table for %s with %llu RX ring(s):\n",
- ctx->devname, ring_count->data);
-
- if (!indir_size)
- printf("Operation not supported\n");
-
- for (i = 0; i < indir_size; i++) {
- if (i % 8 == 0)
- printf("%5u: ", i);
- printf(" %5u", indir[i]);
- if (i % 8 == 7 || i == indir_size - 1)
- fputc('\n', stdout);
- }
-}
-
static int do_grxfhindir(struct cmd_context *ctx,
struct ethtool_rxnfc *ring_count)
{
@@ -3812,7 +3937,8 @@ static int do_grxfhindir(struct cmd_context *ctx,
return 1;
}
- print_indir_table(ctx, ring_count, indir->size, indir->ring_index);
+ print_indir_table(ctx, ring_count->data, indir->size,
+ indir->ring_index);
free(indir);
return 0;
@@ -3826,8 +3952,8 @@ static int do_grxfh(struct cmd_context *ctx)
struct ethtool_rxfh *rss;
u32 rss_context = 0;
u32 i, indir_bytes;
- int arg_num = 0;
- char *hkey;
+ unsigned int arg_num = 0;
+ u8 *hkey;
int err;
while (arg_num < ctx->argc) {
@@ -3877,21 +4003,13 @@ static int do_grxfh(struct cmd_context *ctx)
return 1;
}
- print_indir_table(ctx, &ring_count, rss->indir_size, rss->rss_config);
+ print_indir_table(ctx, ring_count.data, rss->indir_size,
+ rss->rss_config);
indir_bytes = rss->indir_size * sizeof(rss->rss_config[0]);
- hkey = ((char *)rss->rss_config + indir_bytes);
+ hkey = ((u8 *)rss->rss_config + indir_bytes);
- printf("RSS hash key:\n");
- if (!rss->key_size)
- printf("Operation not supported\n");
-
- for (i = 0; i < rss->key_size; i++) {
- if (i == (rss->key_size - 1))
- printf("%02x\n", (u8) hkey[i]);
- else
- printf("%02x:", (u8) hkey[i]);
- }
+ print_rss_hkey(hkey, rss->key_size);
printf("RSS hash function:\n");
if (!rss->hfunc) {
@@ -4024,7 +4142,7 @@ static int do_srxfh(struct cmd_context *ctx)
char *hfunc_name = NULL;
char *hkey = NULL;
int err = 0;
- int i;
+ unsigned int i;
u32 arg_num = 0, indir_bytes = 0;
u32 req_hfunc = 0;
u32 entry_size = sizeof(rss_head.rss_config[0]);
@@ -4290,7 +4408,8 @@ static int do_flash(struct cmd_context *ctx)
static int do_permaddr(struct cmd_context *ctx)
{
- int i, err;
+ unsigned int i;
+ int err;
struct ethtool_perm_addr *epaddr;
epaddr = malloc(sizeof(struct ethtool_perm_addr) + MAX_ADDR_LEN);
@@ -4506,7 +4625,7 @@ static int do_getfwdump(struct cmd_context *ctx)
err = send_ioctl(ctx, &edata);
if (err < 0) {
- perror("Can not get dump level\n");
+ perror("Can not get dump level");
return 1;
}
if (dump_flag != ETHTOOL_GET_DUMP_DATA) {
@@ -4516,14 +4635,14 @@ static int do_getfwdump(struct cmd_context *ctx)
}
data = calloc(1, offsetof(struct ethtool_dump, data) + edata.len);
if (!data) {
- perror("Can not allocate enough memory\n");
+ perror("Can not allocate enough memory");
return 1;
}
data->cmd = ETHTOOL_GET_DUMP_DATA;
data->len = edata.len;
err = send_ioctl(ctx, data);
if (err < 0) {
- perror("Can not get dump data\n");
+ perror("Can not get dump data");
err = 1;
goto free;
}
@@ -4547,7 +4666,7 @@ static int do_setfwdump(struct cmd_context *ctx)
dump.flag = dump_flag;
err = send_ioctl(ctx, &dump);
if (err < 0) {
- perror("Can not set dump level\n");
+ perror("Can not set dump level");
return 1;
}
return 0;
@@ -4697,17 +4816,35 @@ static int do_getmodule(struct cmd_context *ctx)
struct ethtool_modinfo modinfo;
struct ethtool_eeprom *eeprom;
u32 geeprom_offset = 0;
- u32 geeprom_length = -1;
+ u32 geeprom_length = 0;
int geeprom_changed = 0;
int geeprom_dump_raw = 0;
int geeprom_dump_hex = 0;
+ int geeprom_length_seen = 0;
int err;
struct cmdline_info cmdline_geeprom[] = {
- { "offset", CMDL_U32, &geeprom_offset, NULL },
- { "length", CMDL_U32, &geeprom_length, NULL },
- { "raw", CMDL_BOOL, &geeprom_dump_raw, NULL },
- { "hex", CMDL_BOOL, &geeprom_dump_hex, NULL },
+ {
+ .name = "offset",
+ .type = CMDL_U32,
+ .wanted_val = &geeprom_offset,
+ },
+ {
+ .name = "length",
+ .type = CMDL_U32,
+ .wanted_val = &geeprom_length,
+ .seen_val = &geeprom_length_seen,
+ },
+ {
+ .name = "raw",
+ .type = CMDL_BOOL,
+ .wanted_val = &geeprom_dump_raw,
+ },
+ {
+ .name = "hex",
+ .type = CMDL_BOOL,
+ .wanted_val = &geeprom_dump_hex,
+ },
};
parse_generic_cmdline(ctx, &geeprom_changed,
@@ -4725,7 +4862,7 @@ static int do_getmodule(struct cmd_context *ctx)
return 1;
}
- if (geeprom_length == -1)
+ if (!geeprom_length_seen)
geeprom_length = modinfo.eeprom_len;
if (modinfo.eeprom_len < geeprom_offset + geeprom_length)
@@ -4742,7 +4879,12 @@ static int do_getmodule(struct cmd_context *ctx)
eeprom->offset = geeprom_offset;
err = send_ioctl(ctx, eeprom);
if (err < 0) {
+ int saved_errno = errno;
+
perror("Cannot get Module EEPROM data");
+ if (saved_errno == ENODEV || saved_errno == EIO ||
+ saved_errno == ENXIO)
+ fprintf(stderr, "SFP module not in cage?\n");
free(eeprom);
return 1;
}
@@ -4767,16 +4909,16 @@ static int do_getmodule(struct cmd_context *ctx)
switch (modinfo.type) {
#ifdef ETHTOOL_ENABLE_PRETTY_DUMP
case ETH_MODULE_SFF_8079:
- sff8079_show_all(eeprom->data);
+ sff8079_show_all_ioctl(eeprom->data);
break;
case ETH_MODULE_SFF_8472:
- sff8079_show_all(eeprom->data);
+ sff8079_show_all_ioctl(eeprom->data);
sff8472_show_all(eeprom->data);
break;
case ETH_MODULE_SFF_8436:
case ETH_MODULE_SFF_8636:
- sff8636_show_all(eeprom->data,
- modinfo.eeprom_len);
+ sff8636_show_all_ioctl(eeprom->data,
+ modinfo.eeprom_len);
break;
#endif
default:
@@ -4819,10 +4961,30 @@ static int do_seee(struct cmd_context *ctx)
int change = -1, change2 = 0;
struct ethtool_eee eeecmd;
struct cmdline_info cmdline_eee[] = {
- { "advertise", CMDL_U32, &adv_c, &eeecmd.advertised },
- { "tx-lpi", CMDL_BOOL, &lpi_c, &eeecmd.tx_lpi_enabled },
- { "tx-timer", CMDL_U32, &lpi_time_c, &eeecmd.tx_lpi_timer},
- { "eee", CMDL_BOOL, &eee_c, &eeecmd.eee_enabled},
+ {
+ .name = "advertise",
+ .type = CMDL_U32,
+ .wanted_val = &adv_c,
+ .ioctl_val = &eeecmd.advertised,
+ },
+ {
+ .name = "tx-lpi",
+ .type = CMDL_BOOL,
+ .wanted_val = &lpi_c,
+ .ioctl_val = &eeecmd.tx_lpi_enabled,
+ },
+ {
+ .name = "tx-timer",
+ .type = CMDL_U32,
+ .wanted_val = &lpi_time_c,
+ .ioctl_val = &eeecmd.tx_lpi_timer,
+ },
+ {
+ .name = "eee",
+ .type = CMDL_BOOL,
+ .wanted_val = &eee_c,
+ .ioctl_val = &eeecmd.eee_enabled,
+ },
};
if (ctx->argc == 0)
@@ -4850,9 +5012,193 @@ static int do_seee(struct cmd_context *ctx)
return 0;
}
+/* copy of net/ethtool/common.c */
+char
+tunable_strings[__ETHTOOL_TUNABLE_COUNT][ETH_GSTRING_LEN] = {
+ [ETHTOOL_ID_UNSPEC] = "Unspec",
+ [ETHTOOL_RX_COPYBREAK] = "rx-copybreak",
+ [ETHTOOL_TX_COPYBREAK] = "tx-copybreak",
+ [ETHTOOL_TX_COPYBREAK_BUF_SIZE] = "tx-buf-size",
+ [ETHTOOL_PFC_PREVENTION_TOUT] = "pfc-prevention-tout",
+};
+
+union ethtool_tunable_info_val {
+ uint8_t u8;
+ uint16_t u16;
+ uint32_t u32;
+ uint64_t u64;
+ int8_t s8;
+ int16_t s16;
+ int32_t s32;
+ int64_t s64;
+};
+
+struct ethtool_tunable_info {
+ enum tunable_id t_id;
+ enum tunable_type_id t_type_id;
+ size_t size;
+ cmdline_type_t type;
+ union ethtool_tunable_info_val wanted;
+ int seen;
+};
+
+static struct ethtool_tunable_info tunables_info[] = {
+ { .t_id = ETHTOOL_RX_COPYBREAK,
+ .t_type_id = ETHTOOL_TUNABLE_U32,
+ .size = sizeof(u32),
+ .type = CMDL_U32,
+ },
+ { .t_id = ETHTOOL_TX_COPYBREAK,
+ .t_type_id = ETHTOOL_TUNABLE_U32,
+ .size = sizeof(u32),
+ .type = CMDL_U32,
+ },
+ { .t_id = ETHTOOL_PFC_PREVENTION_TOUT,
+ .t_type_id = ETHTOOL_TUNABLE_U16,
+ .size = sizeof(u16),
+ .type = CMDL_U16,
+ },
+ { .t_id = ETHTOOL_TX_COPYBREAK_BUF_SIZE,
+ .t_type_id = ETHTOOL_TUNABLE_U32,
+ .size = sizeof(u32),
+ .type = CMDL_U32,
+ },
+};
+#define TUNABLES_INFO_SIZE ARRAY_SIZE(tunables_info)
+
+static int do_stunable(struct cmd_context *ctx)
+{
+ struct cmdline_info cmdline_tunable[TUNABLES_INFO_SIZE];
+ struct ethtool_tunable_info *tinfo = tunables_info;
+ int changed = 0;
+ unsigned int i;
+
+ for (i = 0; i < TUNABLES_INFO_SIZE; i++) {
+ cmdline_tunable[i].name = tunable_strings[tinfo[i].t_id];
+ cmdline_tunable[i].type = tinfo[i].type;
+ cmdline_tunable[i].wanted_val = &tinfo[i].wanted;
+ cmdline_tunable[i].seen_val = &tinfo[i].seen;
+ }
+
+ parse_generic_cmdline(ctx, &changed, cmdline_tunable, TUNABLES_INFO_SIZE);
+ if (!changed)
+ exit_bad_args();
+
+ for (i = 0; i < TUNABLES_INFO_SIZE; i++) {
+ struct ethtool_tunable *tuna;
+ size_t size;
+ int ret;
+
+ if (!tinfo[i].seen)
+ continue;
+
+ size = sizeof(*tuna) + tinfo[i].size;
+ tuna = calloc(1, size);
+ if (!tuna) {
+ perror(tunable_strings[tinfo[i].t_id]);
+ return 1;
+ }
+ tuna->cmd = ETHTOOL_STUNABLE;
+ tuna->id = tinfo[i].t_id;
+ tuna->type_id = tinfo[i].t_type_id;
+ tuna->len = tinfo[i].size;
+ memcpy(tuna->data, &tinfo[i].wanted, tuna->len);
+ ret = send_ioctl(ctx, tuna);
+ if (ret) {
+ perror(tunable_strings[tuna->id]);
+ free(tuna);
+ return ret;
+ }
+ free(tuna);
+ }
+ return 0;
+}
+
+static void print_tunable(struct ethtool_tunable *tuna)
+{
+ char *name = tunable_strings[tuna->id];
+ union ethtool_tunable_info_val *val;
+
+ val = (union ethtool_tunable_info_val *)tuna->data;
+ switch (tuna->type_id) {
+ case ETHTOOL_TUNABLE_U8:
+ fprintf(stdout, "%s: %" PRIu8 "\n", name, val->u8);
+ break;
+ case ETHTOOL_TUNABLE_U16:
+ fprintf(stdout, "%s: %" PRIu16 "\n", name, val->u16);
+ break;
+ case ETHTOOL_TUNABLE_U32:
+ fprintf(stdout, "%s: %" PRIu32 "\n", name, val->u32);
+ break;
+ case ETHTOOL_TUNABLE_U64:
+ fprintf(stdout, "%s: %" PRIu64 "\n", name, val->u64);
+ break;
+ case ETHTOOL_TUNABLE_S8:
+ fprintf(stdout, "%s: %" PRId8 "\n", name, val->s8);
+ break;
+ case ETHTOOL_TUNABLE_S16:
+ fprintf(stdout, "%s: %" PRId16 "\n", name, val->s16);
+ break;
+ case ETHTOOL_TUNABLE_S32:
+ fprintf(stdout, "%s: %" PRId32 "\n", name, val->s32);
+ break;
+ case ETHTOOL_TUNABLE_S64:
+ fprintf(stdout, "%s: %" PRId64 "\n", name, val->s64);
+ break;
+ default:
+ fprintf(stdout, "%s: Unknown format\n", name);
+ }
+}
+
+static int do_gtunable(struct cmd_context *ctx)
+{
+ struct ethtool_tunable_info *tinfo = tunables_info;
+ char **argp = ctx->argp;
+ unsigned int argc = ctx->argc;
+ unsigned int i, j;
+
+ if (argc < 1)
+ exit_bad_args();
+
+ for (i = 0; i < argc; i++) {
+ int valid = 0;
+
+ for (j = 0; j < TUNABLES_INFO_SIZE; j++) {
+ char *ts = tunable_strings[tinfo[j].t_id];
+ struct ethtool_tunable *tuna;
+ int ret;
+
+ if (strcmp(argp[i], ts))
+ continue;
+ valid = 1;
+
+ tuna = calloc(1, sizeof(*tuna) + tinfo[j].size);
+ if (!tuna) {
+ perror(ts);
+ return 1;
+ }
+ tuna->cmd = ETHTOOL_GTUNABLE;
+ tuna->id = tinfo[j].t_id;
+ tuna->type_id = tinfo[j].t_type_id;
+ tuna->len = tinfo[j].size;
+ ret = send_ioctl(ctx, tuna);
+ if (ret) {
+ fprintf(stderr, "%s: Cannot get tunable\n", ts);
+ free(tuna);
+ return ret;
+ }
+ print_tunable(tuna);
+ free(tuna);
+ }
+ if (!valid)
+ exit_bad_args();
+ }
+ return 0;
+}
+
static int do_get_phy_tunable(struct cmd_context *ctx)
{
- int argc = ctx->argc;
+ unsigned int argc = ctx->argc;
char **argp = ctx->argp;
if (argc < 1)
@@ -4956,9 +5302,9 @@ static int do_reset(struct cmd_context *ctx)
{
struct ethtool_value resetinfo;
__u32 data;
- int argc = ctx->argc;
+ unsigned int argc = ctx->argc;
char **argp = ctx->argp;
- int i;
+ unsigned int i;
if (argc == 0)
exit_bad_args();
@@ -5209,7 +5555,8 @@ static int fecmode_str_to_type(const char *str)
return ETHTOOL_FEC_RS;
if (!strcasecmp(str, "baser"))
return ETHTOOL_FEC_BASER;
-
+ if (!strcasecmp(str, "llrs"))
+ return ETHTOOL_FEC_LLRS;
return 0;
}
@@ -5229,7 +5576,7 @@ static int do_gfec(struct cmd_context *ctx)
}
fprintf(stdout, "FEC parameters for %s:\n", ctx->devname);
- fprintf(stdout, "Configured FEC encodings:");
+ fprintf(stdout, "Supported/Configured FEC encodings:");
dump_fec(feccmd.fec);
fprintf(stdout, "\n");
@@ -5245,7 +5592,8 @@ static int do_sfec(struct cmd_context *ctx)
enum { ARG_NONE, ARG_ENCODING } state = ARG_NONE;
struct ethtool_fecparam feccmd;
int fecmode = 0, newmode;
- int rv, i;
+ unsigned int i;
+ int rv;
for (i = 0; i < ctx->argc; i++) {
if (!strcmp(ctx->argp[i], "encoding")) {
@@ -5288,222 +5636,540 @@ int send_ioctl(struct cmd_context *ctx, void *cmd)
static int show_usage(struct cmd_context *ctx);
-static const struct option {
- const char *opts;
- int want_device;
- int (*func)(struct cmd_context *);
- char *help;
- char *opthelp;
-} args[] = {
- { "-s|--change", 1, do_sset, "Change generic options",
- " [ speed %d ]\n"
- " [ duplex half|full ]\n"
- " [ port tp|aui|bnc|mii|fibre ]\n"
- " [ mdix auto|on|off ]\n"
- " [ autoneg on|off ]\n"
- " [ advertise %x ]\n"
- " [ phyad %d ]\n"
- " [ xcvr internal|external ]\n"
- " [ wol p|u|m|b|a|g|s|f|d... ]\n"
- " [ sopass %x:%x:%x:%x:%x:%x ]\n"
- " [ msglvl %d | msglvl type on|off ... ]\n" },
- { "-a|--show-pause", 1, do_gpause, "Show pause options" },
- { "-A|--pause", 1, do_spause, "Set pause options",
- " [ autoneg on|off ]\n"
- " [ rx on|off ]\n"
- " [ tx on|off ]\n" },
- { "-c|--show-coalesce", 1, do_gcoalesce, "Show coalesce options" },
- { "-C|--coalesce", 1, do_scoalesce, "Set coalesce options",
- " [adaptive-rx on|off]\n"
- " [adaptive-tx on|off]\n"
- " [rx-usecs N]\n"
- " [rx-frames N]\n"
- " [rx-usecs-irq N]\n"
- " [rx-frames-irq N]\n"
- " [tx-usecs N]\n"
- " [tx-frames N]\n"
- " [tx-usecs-irq N]\n"
- " [tx-frames-irq N]\n"
- " [stats-block-usecs N]\n"
- " [pkt-rate-low N]\n"
- " [rx-usecs-low N]\n"
- " [rx-frames-low N]\n"
- " [tx-usecs-low N]\n"
- " [tx-frames-low N]\n"
- " [pkt-rate-high N]\n"
- " [rx-usecs-high N]\n"
- " [rx-frames-high N]\n"
- " [tx-usecs-high N]\n"
- " [tx-frames-high N]\n"
- " [sample-interval N]\n" },
- { "-g|--show-ring", 1, do_gring, "Query RX/TX ring parameters" },
- { "-G|--set-ring", 1, do_sring, "Set RX/TX ring parameters",
- " [ rx N ]\n"
- " [ rx-mini N ]\n"
- " [ rx-jumbo N ]\n"
- " [ tx N ]\n" },
- { "-k|--show-features|--show-offload", 1, do_gfeatures,
- "Get state of protocol offload and other features" },
- { "-K|--features|--offload", 1, do_sfeatures,
- "Set protocol offload and other features",
- " FEATURE on|off ...\n" },
- { "-i|--driver", 1, do_gdrv, "Show driver information" },
- { "-d|--register-dump", 1, do_gregs, "Do a register dump",
- " [ raw on|off ]\n"
- " [ file FILENAME ]\n" },
- { "-e|--eeprom-dump", 1, do_geeprom, "Do a EEPROM dump",
- " [ raw on|off ]\n"
- " [ offset N ]\n"
- " [ length N ]\n" },
- { "-E|--change-eeprom", 1, do_seeprom,
- "Change bytes in device EEPROM",
- " [ magic N ]\n"
- " [ offset N ]\n"
- " [ length N ]\n"
- " [ value N ]\n" },
- { "-r|--negotiate", 1, do_nway_rst, "Restart N-WAY negotiation" },
- { "-p|--identify", 1, do_phys_id,
- "Show visible port identification (e.g. blinking)",
- " [ TIME-IN-SECONDS ]\n" },
- { "-t|--test", 1, do_test, "Execute adapter self test",
- " [ online | offline | external_lb ]\n" },
- { "-S|--statistics", 1, do_gnicstats, "Show adapter statistics" },
- { "--phy-statistics", 1, do_gphystats,
- "Show phy statistics" },
- { "-n|-u|--show-nfc|--show-ntuple", 1, do_grxclass,
- "Show Rx network flow classification options or rules",
- " [ rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|"
- "tcp6|udp6|ah6|esp6|sctp6 [context %d] |\n"
- " rule %d ]\n" },
- { "-N|-U|--config-nfc|--config-ntuple", 1, do_srxclass,
- "Configure Rx network flow classification options or rules",
- " rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|"
- "tcp6|udp6|ah6|esp6|sctp6 m|v|t|s|d|f|n|r... [context %d] |\n"
- " flow-type ether|ip4|tcp4|udp4|sctp4|ah4|esp4|"
- "ip6|tcp6|udp6|ah6|esp6|sctp6\n"
- " [ src %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n"
- " [ dst %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n"
- " [ proto %d [m %x] ]\n"
- " [ src-ip IP-ADDRESS [m IP-ADDRESS] ]\n"
- " [ dst-ip IP-ADDRESS [m IP-ADDRESS] ]\n"
- " [ tos %d [m %x] ]\n"
- " [ tclass %d [m %x] ]\n"
- " [ l4proto %d [m %x] ]\n"
- " [ src-port %d [m %x] ]\n"
- " [ dst-port %d [m %x] ]\n"
- " [ spi %d [m %x] ]\n"
- " [ vlan-etype %x [m %x] ]\n"
- " [ vlan %x [m %x] ]\n"
- " [ user-def %x [m %x] ]\n"
- " [ dst-mac %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n"
- " [ action %d ] | [ vf %d queue %d ]\n"
- " [ context %d ]\n"
- " [ loc %d]] |\n"
- " delete %d\n" },
- { "-T|--show-time-stamping", 1, do_tsinfo,
- "Show time stamping capabilities" },
- { "-x|--show-rxfh-indir|--show-rxfh", 1, do_grxfh,
- "Show Rx flow hash indirection table and/or RSS hash key",
- " [ context %d ]\n" },
- { "-X|--set-rxfh-indir|--rxfh", 1, do_srxfh,
- "Set Rx flow hash indirection table and/or RSS hash key",
- " [ context %d|new ]\n"
- " [ equal N | weight W0 W1 ... | default ]\n"
- " [ hkey %x:%x:%x:%x:%x:.... ]\n"
- " [ hfunc FUNC ]\n"
- " [ delete ]\n" },
- { "-f|--flash", 1, do_flash,
- "Flash firmware image from the specified file to a region on the device",
- " FILENAME [ REGION-NUMBER-TO-FLASH ]\n" },
- { "-P|--show-permaddr", 1, do_permaddr,
- "Show permanent hardware address" },
- { "-w|--get-dump", 1, do_getfwdump,
- "Get dump flag, data",
- " [ data FILENAME ]\n" },
- { "-W|--set-dump", 1, do_setfwdump,
- "Set dump flag of the device",
- " N\n"},
- { "-l|--show-channels", 1, do_gchannels, "Query Channels" },
- { "-L|--set-channels", 1, do_schannels, "Set Channels",
- " [ rx N ]\n"
- " [ tx N ]\n"
- " [ other N ]\n"
- " [ combined N ]\n" },
- { "--show-priv-flags", 1, do_gprivflags, "Query private flags" },
- { "--set-priv-flags", 1, do_sprivflags, "Set private flags",
- " FLAG on|off ...\n" },
- { "-m|--dump-module-eeprom|--module-info", 1, do_getmodule,
- "Query/Decode Module EEPROM information and optical diagnostics if available",
- " [ raw on|off ]\n"
- " [ hex on|off ]\n"
- " [ offset N ]\n"
- " [ length N ]\n" },
- { "--show-eee", 1, do_geee, "Show EEE settings"},
- { "--set-eee", 1, do_seee, "Set EEE settings",
- " [ eee on|off ]\n"
- " [ advertise %x ]\n"
- " [ tx-lpi on|off ]\n"
- " [ tx-timer %d ]\n"},
- { "--set-phy-tunable", 1, do_set_phy_tunable, "Set PHY tunable",
- " [ downshift on|off [count N] ]\n"
- " [ fast-link-down on|off [msecs N] ]\n"
- " [ energy-detect-power-down on|off [msecs N] ]\n"},
- { "--get-phy-tunable", 1, do_get_phy_tunable, "Get PHY tunable",
- " [ downshift ]\n"
- " [ fast-link-down ]\n"
- " [ energy-detect-power-down ]\n"},
- { "--reset", 1, do_reset, "Reset components",
- " [ flags %x ]\n"
- " [ mgmt ]\n"
- " [ mgmt-shared ]\n"
- " [ irq ]\n"
- " [ irq-shared ]\n"
- " [ dma ]\n"
- " [ dma-shared ]\n"
- " [ filter ]\n"
- " [ filter-shared ]\n"
- " [ offload ]\n"
- " [ offload-shared ]\n"
- " [ mac ]\n"
- " [ mac-shared ]\n"
- " [ phy ]\n"
- " [ phy-shared ]\n"
- " [ ram ]\n"
- " [ ram-shared ]\n"
- " [ ap ]\n"
- " [ ap-shared ]\n"
- " [ dedicated ]\n"
- " [ all ]\n"},
- { "--show-fec", 1, do_gfec, "Show FEC settings"},
- { "--set-fec", 1, do_sfec, "Set FEC settings",
- " [ encoding auto|off|rs|baser [...]]\n"},
- { "-Q|--per-queue", 1, do_perqueue, "Apply per-queue command."
- "The supported sub commands include --show-coalesce, --coalesce",
- " [queue_mask %x] SUB_COMMAND\n"},
- { "-h|--help", 0, show_usage, "Show this help" },
- { "--version", 0, do_version, "Show version number" },
+struct option {
+ const char *opts;
+ bool no_dev;
+ bool json;
+ int (*func)(struct cmd_context *);
+ nl_chk_t nlchk;
+ nl_func_t nlfunc;
+ const char *help;
+ const char *xhelp;
+};
+
+static const struct option args[] = {
+ {
+ /* "default" entry when no switch is used */
+ .opts = "",
+ .func = do_gset,
+ .nlfunc = nl_gset,
+ .help = "Display standard information about device",
+ },
+ {
+ .opts = "-s|--change",
+ .func = do_sset,
+ .nlfunc = nl_sset,
+ .help = "Change generic options",
+ .xhelp = " [ speed %d ]\n"
+ " [ lanes %d ]\n"
+ " [ duplex half|full ]\n"
+ " [ port tp|aui|bnc|mii|fibre|da ]\n"
+ " [ mdix auto|on|off ]\n"
+ " [ autoneg on|off ]\n"
+ " [ advertise %x[/%x] | mode on|off ... [--] ]\n"
+ " [ phyad %d ]\n"
+ " [ xcvr internal|external ]\n"
+ " [ wol %d[/%d] | p|u|m|b|a|g|s|f|d... ]\n"
+ " [ sopass %x:%x:%x:%x:%x:%x ]\n"
+ " [ msglvl %d[/%d] | type on|off ... [--] ]\n"
+ " [ master-slave preferred-master|preferred-slave|forced-master|forced-slave ]\n"
+ },
+ {
+ .opts = "-a|--show-pause",
+ .json = true,
+ .func = do_gpause,
+ .nlfunc = nl_gpause,
+ .help = "Show pause options",
+ .xhelp = " [ --src aggregate | emac | pmac ]\n"
+ },
+ {
+ .opts = "-A|--pause",
+ .func = do_spause,
+ .nlfunc = nl_spause,
+ .help = "Set pause options",
+ .xhelp = " [ autoneg on|off ]\n"
+ " [ rx on|off ]\n"
+ " [ tx on|off ]\n"
+ },
+ {
+ .opts = "-c|--show-coalesce",
+ .json = true,
+ .func = do_gcoalesce,
+ .nlfunc = nl_gcoalesce,
+ .help = "Show coalesce options"
+ },
+ {
+ .opts = "-C|--coalesce",
+ .func = do_scoalesce,
+ .nlfunc = nl_scoalesce,
+ .help = "Set coalesce options",
+ .xhelp = " [adaptive-rx on|off]\n"
+ " [adaptive-tx on|off]\n"
+ " [rx-usecs N]\n"
+ " [rx-frames N]\n"
+ " [rx-usecs-irq N]\n"
+ " [rx-frames-irq N]\n"
+ " [tx-usecs N]\n"
+ " [tx-frames N]\n"
+ " [tx-usecs-irq N]\n"
+ " [tx-frames-irq N]\n"
+ " [stats-block-usecs N]\n"
+ " [pkt-rate-low N]\n"
+ " [rx-usecs-low N]\n"
+ " [rx-frames-low N]\n"
+ " [tx-usecs-low N]\n"
+ " [tx-frames-low N]\n"
+ " [pkt-rate-high N]\n"
+ " [rx-usecs-high N]\n"
+ " [rx-frames-high N]\n"
+ " [tx-usecs-high N]\n"
+ " [tx-frames-high N]\n"
+ " [sample-interval N]\n"
+ " [cqe-mode-rx on|off]\n"
+ " [cqe-mode-tx on|off]\n"
+ " [tx-aggr-max-bytes N]\n"
+ " [tx-aggr-max-frames N]\n"
+ " [tx-aggr-time-usecs N]\n"
+ },
+ {
+ .opts = "-g|--show-ring",
+ .json = true,
+ .func = do_gring,
+ .nlfunc = nl_gring,
+ .help = "Query RX/TX ring parameters"
+ },
+ {
+ .opts = "-G|--set-ring",
+ .func = do_sring,
+ .nlfunc = nl_sring,
+ .help = "Set RX/TX ring parameters",
+ .xhelp = " [ rx N ]\n"
+ " [ rx-mini N ]\n"
+ " [ rx-jumbo N ]\n"
+ " [ tx N ]\n"
+ " [ rx-buf-len N ]\n"
+ " [ cqe-size N ]\n"
+ " [ tx-push on|off ]\n"
+ " [ rx-push on|off ]\n"
+ " [ tx-push-buf-len N]\n"
+ },
+ {
+ .opts = "-k|--show-features|--show-offload",
+ .json = true,
+ .func = do_gfeatures,
+ .nlfunc = nl_gfeatures,
+ .help = "Get state of protocol offload and other features"
+ },
+ {
+ .opts = "-K|--features|--offload",
+ .func = do_sfeatures,
+ .nlfunc = nl_sfeatures,
+ .help = "Set protocol offload and other features",
+ .xhelp = " FEATURE on|off ...\n"
+ },
+ {
+ .opts = "-i|--driver",
+ .func = do_gdrv,
+ .help = "Show driver information"
+ },
+ {
+ .opts = "-d|--register-dump",
+ .func = do_gregs,
+ .help = "Do a register dump",
+ .xhelp = " [ raw on|off ]\n"
+ " [ file FILENAME ]\n"
+ },
+ {
+ .opts = "-e|--eeprom-dump",
+ .func = do_geeprom,
+ .help = "Do a EEPROM dump",
+ .xhelp = " [ raw on|off ]\n"
+ " [ offset N ]\n"
+ " [ length N ]\n"
+ },
+ {
+ .opts = "-E|--change-eeprom",
+ .func = do_seeprom,
+ .help = "Change bytes in device EEPROM",
+ .xhelp = " [ magic N ]\n"
+ " [ offset N ]\n"
+ " [ length N ]\n"
+ " [ value N ]\n"
+ },
+ {
+ .opts = "-r|--negotiate",
+ .func = do_nway_rst,
+ .help = "Restart N-WAY negotiation"
+ },
+ {
+ .opts = "-p|--identify",
+ .func = do_phys_id,
+ .help = "Show visible port identification (e.g. blinking)",
+ .xhelp = " [ TIME-IN-SECONDS ]\n"
+ },
+ {
+ .opts = "-t|--test",
+ .func = do_test,
+ .help = "Execute adapter self test",
+ .xhelp = " [ online | offline | external_lb ]\n"
+ },
+ {
+ .opts = "-S|--statistics",
+ .json = true,
+ .func = do_gnicstats,
+ .nlchk = nl_gstats_chk,
+ .nlfunc = nl_gstats,
+ .help = "Show adapter statistics",
+ .xhelp = " [ --all-groups | --groups [eth-phy] [eth-mac] [eth-ctrl] [rmon] ]\n"
+ " [ --src aggregate | emac | pmac ]\n"
+ },
+ {
+ .opts = "--phy-statistics",
+ .func = do_gphystats,
+ .help = "Show phy statistics"
+ },
+ {
+ .opts = "-n|-u|--show-nfc|--show-ntuple",
+ .func = do_grxclass,
+ .help = "Show Rx network flow classification options or rules",
+ .xhelp = " [ rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|"
+ "tcp6|udp6|ah6|esp6|sctp6 [context %d] |\n"
+ " rule %d ]\n"
+ },
+ {
+ .opts = "-N|-U|--config-nfc|--config-ntuple",
+ .func = do_srxclass,
+ .help = "Configure Rx network flow classification options or rules",
+ .xhelp = " rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|"
+ "tcp6|udp6|ah6|esp6|sctp6 m|v|t|s|d|f|n|r... [context %d] |\n"
+ " flow-type ether|ip4|tcp4|udp4|sctp4|ah4|esp4|"
+ "ip6|tcp6|udp6|ah6|esp6|sctp6\n"
+ " [ src %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n"
+ " [ dst %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n"
+ " [ proto %d [m %x] ]\n"
+ " [ src-ip IP-ADDRESS [m IP-ADDRESS] ]\n"
+ " [ dst-ip IP-ADDRESS [m IP-ADDRESS] ]\n"
+ " [ tos %d [m %x] ]\n"
+ " [ tclass %d [m %x] ]\n"
+ " [ l4proto %d [m %x] ]\n"
+ " [ src-port %d [m %x] ]\n"
+ " [ dst-port %d [m %x] ]\n"
+ " [ spi %d [m %x] ]\n"
+ " [ vlan-etype %x [m %x] ]\n"
+ " [ vlan %x [m %x] ]\n"
+ " [ user-def %x [m %x] ]\n"
+ " [ dst-mac %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n"
+ " [ action %d ] | [ vf %d queue %d ]\n"
+ " [ context %d ]\n"
+ " [ loc %d ] |\n"
+ " delete %d\n"
+ },
+ {
+ .opts = "-T|--show-time-stamping",
+ .func = do_tsinfo,
+ .nlfunc = nl_tsinfo,
+ .help = "Show time stamping capabilities"
+ },
+ {
+ .opts = "-x|--show-rxfh-indir|--show-rxfh",
+ .json = true,
+ .func = do_grxfh,
+ .nlfunc = nl_grss,
+ .help = "Show Rx flow hash indirection table and/or RSS hash key",
+ .xhelp = " [ context %d ]\n"
+ },
+ {
+ .opts = "-X|--set-rxfh-indir|--rxfh",
+ .func = do_srxfh,
+ .help = "Set Rx flow hash indirection table and/or RSS hash key",
+ .xhelp = " [ context %d|new ]\n"
+ " [ equal N | weight W0 W1 ... | default ]\n"
+ " [ hkey %x:%x:%x:%x:%x:.... ]\n"
+ " [ hfunc FUNC ]\n"
+ " [ delete ]\n"
+ },
+ {
+ .opts = "-f|--flash",
+ .func = do_flash,
+ .help = "Flash firmware image from the specified file to a region on the device",
+ .xhelp = " FILENAME [ REGION-NUMBER-TO-FLASH ]\n"
+ },
+ {
+ .opts = "-P|--show-permaddr",
+ .func = do_permaddr,
+ .nlfunc = nl_permaddr,
+ .help = "Show permanent hardware address"
+ },
+ {
+ .opts = "-w|--get-dump",
+ .func = do_getfwdump,
+ .help = "Get dump flag, data",
+ .xhelp = " [ data FILENAME ]\n"
+ },
+ {
+ .opts = "-W|--set-dump",
+ .func = do_setfwdump,
+ .help = "Set dump flag of the device",
+ .xhelp = " N\n"
+ },
+ {
+ .opts = "-l|--show-channels",
+ .func = do_gchannels,
+ .nlfunc = nl_gchannels,
+ .help = "Query Channels"
+ },
+ {
+ .opts = "-L|--set-channels",
+ .func = do_schannels,
+ .nlfunc = nl_schannels,
+ .help = "Set Channels",
+ .xhelp = " [ rx N ]\n"
+ " [ tx N ]\n"
+ " [ other N ]\n"
+ " [ combined N ]\n"
+ },
+ {
+ .opts = "--show-priv-flags",
+ .func = do_gprivflags,
+ .nlfunc = nl_gprivflags,
+ .help = "Query private flags"
+ },
+ {
+ .opts = "--set-priv-flags",
+ .func = do_sprivflags,
+ .nlfunc = nl_sprivflags,
+ .help = "Set private flags",
+ .xhelp = " FLAG on|off ...\n"
+ },
+ {
+ .opts = "-m|--dump-module-eeprom|--module-info",
+ .func = do_getmodule,
+ .nlfunc = nl_getmodule,
+ .help = "Query/Decode Module EEPROM information and optical diagnostics if available",
+ .xhelp = " [ raw on|off ]\n"
+ " [ hex on|off ]\n"
+ " [ offset N ]\n"
+ " [ length N ]\n"
+ " [ page N ]\n"
+ " [ bank N ]\n"
+ " [ i2c N ]\n"
+ },
+ {
+ .opts = "--show-eee",
+ .func = do_geee,
+ .nlfunc = nl_geee,
+ .help = "Show EEE settings",
+ },
+ {
+ .opts = "--set-eee",
+ .func = do_seee,
+ .nlfunc = nl_seee,
+ .help = "Set EEE settings",
+ .xhelp = " [ eee on|off ]\n"
+ " [ advertise %x ]\n"
+ " [ tx-lpi on|off ]\n"
+ " [ tx-timer %d ]\n"
+ },
+ {
+ .opts = "--set-phy-tunable",
+ .func = do_set_phy_tunable,
+ .help = "Set PHY tunable",
+ .xhelp = " [ downshift on|off [count N] ]\n"
+ " [ fast-link-down on|off [msecs N] ]\n"
+ " [ energy-detect-power-down on|off [msecs N] ]\n"
+ },
+ {
+ .opts = "--get-phy-tunable",
+ .func = do_get_phy_tunable,
+ .help = "Get PHY tunable",
+ .xhelp = " [ downshift ]\n"
+ " [ fast-link-down ]\n"
+ " [ energy-detect-power-down ]\n"
+ },
+ {
+ .opts = "--get-tunable",
+ .func = do_gtunable,
+ .help = "Get tunable",
+ .xhelp = " [ rx-copybreak ]\n"
+ " [ tx-copybreak ]\n"
+ " [ tx-buf-size ]\n"
+ " [ pfc-prevention-tout ]\n"
+ },
+ {
+ .opts = "--set-tunable",
+ .func = do_stunable,
+ .help = "Set tunable",
+ .xhelp = " [ rx-copybreak N ]\n"
+ " [ tx-copybreak N ]\n"
+ " [ tx-buf-size N ]\n"
+ " [ pfc-prevention-tout N ]\n"
+ },
+ {
+ .opts = "--reset",
+ .func = do_reset,
+ .help = "Reset components",
+ .xhelp = " [ flags %x ]\n"
+ " [ mgmt ]\n"
+ " [ mgmt-shared ]\n"
+ " [ irq ]\n"
+ " [ irq-shared ]\n"
+ " [ dma ]\n"
+ " [ dma-shared ]\n"
+ " [ filter ]\n"
+ " [ filter-shared ]\n"
+ " [ offload ]\n"
+ " [ offload-shared ]\n"
+ " [ mac ]\n"
+ " [ mac-shared ]\n"
+ " [ phy ]\n"
+ " [ phy-shared ]\n"
+ " [ ram ]\n"
+ " [ ram-shared ]\n"
+ " [ ap ]\n"
+ " [ ap-shared ]\n"
+ " [ dedicated ]\n"
+ " [ all ]\n"
+ },
+ {
+ .opts = "--show-fec",
+ .json = true,
+ .func = do_gfec,
+ .nlfunc = nl_gfec,
+ .help = "Show FEC settings",
+ },
+ {
+ .opts = "--set-fec",
+ .func = do_sfec,
+ .nlfunc = nl_sfec,
+ .help = "Set FEC settings",
+ .xhelp = " [ encoding auto|off|rs|baser|llrs [...] ]\n"
+ },
+ {
+ .opts = "-Q|--per-queue",
+ .func = do_perqueue,
+ .help = "Apply per-queue command. ",
+ .xhelp = "The supported sub commands include --show-coalesce, --coalesce"
+ " [queue_mask %x] SUB_COMMAND\n",
+ },
+ {
+ .opts = "--cable-test",
+ .json = true,
+ .nlfunc = nl_cable_test,
+ .help = "Perform a cable test",
+ },
+ {
+ .opts = "--cable-test-tdr",
+ .json = true,
+ .nlfunc = nl_cable_test_tdr,
+ .help = "Print cable test time domain reflectrometery data",
+ .xhelp = " [ first N ]\n"
+ " [ last N ]\n"
+ " [ step N ]\n"
+ " [ pair N ]\n"
+ },
+ {
+ .opts = "--show-tunnels",
+ .nlfunc = nl_gtunnels,
+ .help = "Show NIC tunnel offload information",
+ },
+ {
+ .opts = "--show-module",
+ .json = true,
+ .nlfunc = nl_gmodule,
+ .help = "Show transceiver module settings",
+ },
+ {
+ .opts = "--set-module",
+ .nlfunc = nl_smodule,
+ .help = "Set transceiver module settings",
+ .xhelp = " [ power-mode-policy high|auto ]\n"
+ },
+ {
+ .opts = "--get-plca-cfg",
+ .nlfunc = nl_plca_get_cfg,
+ .help = "Get PLCA configuration",
+ },
+ {
+ .opts = "--set-plca-cfg",
+ .nlfunc = nl_plca_set_cfg,
+ .help = "Set PLCA configuration",
+ .xhelp = " [ enable on|off ]\n"
+ " [ node-id N ]\n"
+ " [ node-cnt N ]\n"
+ " [ to-tmr N ]\n"
+ " [ burst-cnt N ]\n"
+ " [ burst-tmr N ]\n"
+ },
+ {
+ .opts = "--get-plca-status",
+ .nlfunc = nl_plca_get_status,
+ .help = "Get PLCA status information",
+ },
+ {
+ .opts = "--show-mm",
+ .json = true,
+ .nlfunc = nl_get_mm,
+ .help = "Show MAC merge layer state",
+ },
+ {
+ .opts = "--set-mm",
+ .nlfunc = nl_set_mm,
+ .help = "Set MAC merge layer parameters",
+ " [ verify-enabled on|off ]\n"
+ " [ verify-time N ]\n"
+ " [ tx-enabled on|off ]\n"
+ " [ pmac-enabled on|off ]\n"
+ " [ tx-min-frag-size 60-252 ]\n"
+ },
+ {
+ .opts = "--show-pse",
+ .json = true,
+ .nlfunc = nl_gpse,
+ .help = "Show settings for Power Sourcing Equipment",
+ },
+ {
+ .opts = "--set-pse",
+ .nlfunc = nl_spse,
+ .help = "Set Power Sourcing Equipment settings",
+ .xhelp = " [ podl-pse-admin-control enable|disable ]\n"
+ },
+ {
+ .opts = "-h|--help",
+ .no_dev = true,
+ .func = show_usage,
+ .help = "Show this help"
+ },
+ {
+ .opts = "--version",
+ .no_dev = true,
+ .func = do_version,
+ .help = "Show version number"
+ },
{}
};
-static int show_usage(struct cmd_context *ctx maybe_unused)
+static int show_usage(struct cmd_context *ctx __maybe_unused)
{
int i;
/* ethtool -h */
fprintf(stdout, PACKAGE " version " VERSION "\n");
- fprintf(stdout,
- "Usage:\n"
- " ethtool DEVNAME\t"
- "Display standard information about device\n");
+ fprintf(stdout, "Usage:\n");
for (i = 0; args[i].opts; i++) {
- fputs(" ethtool ", stdout);
+ fputs(" ethtool [ FLAGS ] ", stdout);
fprintf(stdout, "%s %s\t%s\n",
args[i].opts,
- args[i].want_device ? "DEVNAME" : "\t",
+ args[i].no_dev ? "\t" : "DEVNAME",
args[i].help);
- if (args[i].opthelp)
- fputs(args[i].opthelp, stdout);
+ if (args[i].xhelp)
+ fputs(args[i].xhelp, stdout);
}
+ nl_monitor_usage();
+ fprintf(stdout, "\n");
+ fprintf(stdout, "FLAGS:\n");
+ fprintf(stdout, " --debug MASK turn on debugging messages\n");
+ fprintf(stdout, " --json enable JSON output format (not supported by all commands)\n");
+ fprintf(stdout, " -I|--include-statistics request device statistics related to the command (not supported by all commands)\n");
return 0;
}
@@ -5514,7 +6180,7 @@ static int find_option(char *arg)
size_t len;
int k;
- for (k = 0; args[k].opts; k++) {
+ for (k = 1; args[k].opts; k++) {
opt = args[k].opts;
for (;;) {
len = strcspn(opt, "|");
@@ -5647,6 +6313,8 @@ static int do_perqueue(struct cmd_context *ctx)
"The sub commands will be applied to all %d queues\n",
n_queues);
} else {
+ if (ctx->argc <= 2)
+ exit_bad_args();
ctx->argc--;
ctx->argp++;
if (parse_hex_u32_bitmap(*ctx->argp, MAX_NUM_QUEUE,
@@ -5699,67 +6367,121 @@ static int do_perqueue(struct cmd_context *ctx)
return 0;
}
+static int ioctl_init(struct cmd_context *ctx, bool no_dev)
+{
+ if (no_dev) {
+ ctx->fd = -1;
+ return 0;
+ }
+ if (strlen(ctx->devname) >= IFNAMSIZ) {
+ fprintf(stderr, "Device name longer than %u characters\n",
+ IFNAMSIZ - 1);
+ exit_bad_args();
+ }
+
+ /* Setup our control structures. */
+ memset(&ctx->ifr, 0, sizeof(ctx->ifr));
+ strcpy(ctx->ifr.ifr_name, ctx->devname);
+
+ /* Open control socket. */
+ ctx->fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (ctx->fd < 0)
+ ctx->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (ctx->fd < 0) {
+ perror("Cannot get control socket");
+ return 70;
+ }
+
+ return 0;
+}
+
int main(int argc, char **argp)
{
- int (*func)(struct cmd_context *);
- int want_device;
- struct cmd_context ctx;
+ struct cmd_context ctx = {};
+ int ret;
int k;
init_global_link_mode_masks();
+ if (argc < 2)
+ exit_bad_args();
+
/* Skip command name */
argp++;
argc--;
+ while (true) {
+ if (*argp && !strcmp(*argp, "--debug")) {
+ char *eptr;
+
+ if (argc < 2)
+ exit_bad_args();
+ ctx.debug = strtoul(argp[1], &eptr, 0);
+ if (!argp[1][0] || *eptr)
+ exit_bad_args();
+
+ argp += 2;
+ argc -= 2;
+ continue;
+ }
+ if (*argp && !strcmp(*argp, "--json")) {
+ ctx.json = true;
+ argp += 1;
+ argc -= 1;
+ continue;
+ }
+ if (*argp && (!strcmp(*argp, "--include-statistics") ||
+ !strcmp(*argp, "-I"))) {
+ ctx.show_stats = true;
+ argp += 1;
+ argc -= 1;
+ continue;
+ }
+ break;
+ }
+ if (*argp && !strcmp(*argp, "--monitor")) {
+ ctx.argp = ++argp;
+ ctx.argc = --argc;
+ ret = nl_monitor(&ctx);
+ return ret ? 1 : 0;
+ }
+
/* First argument must be either a valid option or a device
* name to get settings for (which we don't expect to begin
* with '-').
*/
- if (argc == 0)
+ if (!*argp)
exit_bad_args();
k = find_option(*argp);
- if (k >= 0) {
+ if (k > 0) {
argp++;
argc--;
- func = args[k].func;
- want_device = args[k].want_device;
- goto opt_found;
+ } else {
+ if ((*argp)[0] == '-')
+ exit_bad_args();
+ k = 0;
}
- if ((*argp)[0] == '-')
- exit_bad_args();
- func = do_gset;
- want_device = 1;
-opt_found:
- if (want_device) {
+ if (!args[k].no_dev) {
ctx.devname = *argp++;
argc--;
- if (ctx.devname == NULL)
+ if (!ctx.devname)
exit_bad_args();
- if (strlen(ctx.devname) >= IFNAMSIZ)
- exit_bad_args();
-
- /* Setup our control structures. */
- memset(&ctx.ifr, 0, sizeof(ctx.ifr));
- strcpy(ctx.ifr.ifr_name, ctx.devname);
-
- /* Open control socket. */
- ctx.fd = socket(AF_INET, SOCK_DGRAM, 0);
- if (ctx.fd < 0)
- ctx.fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
- if (ctx.fd < 0) {
- perror("Cannot get control socket");
- return 70;
- }
- } else {
- ctx.fd = -1;
}
-
+ if (ctx.json && !args[k].json)
+ exit_bad_args();
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();
+
+ ret = ioctl_init(&ctx, args[k].no_dev);
+ if (ret)
+ return ret;
- return func(&ctx);
+ return args[k].func(&ctx);
}