[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <1379978791.2485.87.camel@bwh-desktop.uk.level5networks.com>
Date: Tue, 24 Sep 2013 00:26:31 +0100
From: Ben Hutchings <bhutchings@...arflare.com>
To: <netdev@...r.kernel.org>
CC: <linux-net-drivers@...arflare.com>
Subject: [PATCH ethtool 2/2] Hide state of VLAN tag offload and LRO if the
kernel is too old
Starting with Linux 2.6.37 and ethtool 2.6.36 it was possible to show
the state of VLAN tag offload (using ETHTOOL_GFLAGS). But the state
would always be shown as 'off' for older kernel versions, even though
VLAN tag offload had been implemented long before this.
In ethtool 3.4.2 I attempted to fix this by also reading the state of
VLAN tag offload from the 'features' attribute in sysfs. But this had
to be reverted because it causes 'ethtool -K' to pass the flags back
into ETHTOOL_SFLAGS.
Instead, hide the VLAN tag offload flags if the kernel is older than
2.6.37.
Similarly, LRO was implemented some time before it was exposed through
ETHTOOL_GFLAGS in Linux 2.6.24. So hide the LRO flag if the kernel
is older than that.
Signed-off-by: Ben Hutchings <bhutchings@...arflare.com>
---
ethtool.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 46 insertions(+), 12 deletions(-)
diff --git a/ethtool.c b/ethtool.c
index 2dc07d3..b06dfa3 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -113,6 +113,8 @@ enum {
};
#endif
+#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+
static void exit_bad_args(void) __attribute__((noreturn));
static void exit_bad_args(void)
@@ -183,32 +185,43 @@ struct off_flag_def {
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 },
+ ETHTOOL_GRXCSUM, ETHTOOL_SRXCSUM, ETH_FLAG_RXCSUM, 0 },
{ "tx", "tx-checksumming", "tx-checksum-*",
- ETHTOOL_GTXCSUM, ETHTOOL_STXCSUM, ETH_FLAG_TXCSUM },
+ ETHTOOL_GTXCSUM, ETHTOOL_STXCSUM, ETH_FLAG_TXCSUM, 0 },
{ "sg", "scatter-gather", "tx-scatter-gather*",
- ETHTOOL_GSG, ETHTOOL_SSG, ETH_FLAG_SG },
+ ETHTOOL_GSG, ETHTOOL_SSG, ETH_FLAG_SG, 0 },
{ "tso", "tcp-segmentation-offload", "tx-tcp*-segmentation",
- ETHTOOL_GTSO, ETHTOOL_STSO, ETH_FLAG_TSO },
+ ETHTOOL_GTSO, ETHTOOL_STSO, ETH_FLAG_TSO, 0 },
{ "ufo", "udp-fragmentation-offload", "tx-udp-fragmentation",
- ETHTOOL_GUFO, ETHTOOL_SUFO, ETH_FLAG_UFO },
+ ETHTOOL_GUFO, ETHTOOL_SUFO, ETH_FLAG_UFO, 0 },
{ "gso", "generic-segmentation-offload", "tx-generic-segmentation",
- ETHTOOL_GGSO, ETHTOOL_SGSO, ETH_FLAG_GSO },
+ ETHTOOL_GGSO, ETHTOOL_SGSO, ETH_FLAG_GSO, 0 },
{ "gro", "generic-receive-offload", "rx-gro",
- ETHTOOL_GGRO, ETHTOOL_SGRO, ETH_FLAG_GRO },
+ ETHTOOL_GGRO, ETHTOOL_SGRO, ETH_FLAG_GRO, 0 },
{ "lro", "large-receive-offload", "rx-lro",
- 0, 0, ETH_FLAG_LRO },
+ 0, 0, ETH_FLAG_LRO,
+ KERNEL_VERSION(2,6,24) },
{ "rxvlan", "rx-vlan-offload", "rx-vlan-hw-parse",
- 0, 0, ETH_FLAG_RXVLAN },
+ 0, 0, ETH_FLAG_RXVLAN,
+ KERNEL_VERSION(2,6,37) },
{ "txvlan", "tx-vlan-offload", "tx-vlan-hw-insert",
- 0, 0, ETH_FLAG_TXVLAN },
+ 0, 0, ETH_FLAG_TXVLAN,
+ KERNEL_VERSION(2,6,37) },
{ "ntuple", "ntuple-filters", "rx-ntuple-filter",
- 0, 0, ETH_FLAG_NTUPLE },
+ 0, 0, ETH_FLAG_NTUPLE, 0 },
{ "rxhash", "receive-hashing", "rx-hashing",
- 0, 0, ETH_FLAG_RXHASH },
+ 0, 0, ETH_FLAG_RXHASH, 0 },
};
struct feature_def {
@@ -1179,15 +1192,36 @@ static void dump_one_feature(const char *indent, const char *name,
: "");
}
+static int linux_version_code(void)
+{
+ struct utsname utsname;
+ unsigned version, patchlevel, sublevel = 0;
+
+ if (uname(&utsname))
+ return -1;
+ if (sscanf(utsname.release, "%u.%u.%u", &version, &patchlevel, &sublevel) < 2)
+ return -1;
+ return KERNEL_VERSION(version, patchlevel, sublevel);
+}
+
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;
int indent;
int i, j;
for (i = 0; i < ARRAY_SIZE(off_flag_def); i++) {
+ /* Don't show features whose state is unknown on this
+ * kernel version
+ */
+ if (defs->off_flag_matched[i] == 0 &&
+ off_flag_def[i].get_cmd == 0 &&
+ kernel_ver < off_flag_def[i].min_kernel_ver)
+ continue;
+
value = off_flag_def[i].value;
/* If this offload flag matches exactly one generic
--
1.8.1.4
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists