* Re: [PATCH 3/3] Revert Backoff [v3]: Calculate TCP's connection close threshold as a time value.
From: Jerry Chu @ 2012-06-01 22:58 UTC (permalink / raw)
To: Damian Lukowski; +Cc: Netdev, David Miller, Ilpo Järvinen
In-Reply-To: <CAFbMe2Mu46N8kRrYkGzYRLuntEd2J9aO_d0Jw_y0gsQA4q-qHw@mail.gmail.com>
> From: Damian Lukowski <damian@tvk.rwth-aachen.de>
> Date: Wed, Aug 26, 2009 at 3:16 AM
> Subject: [PATCH 3/3] Revert Backoff [v3]: Calculate TCP's connection close
> threshold as a time value.
> To: Netdev <netdev@vger.kernel.org>
>
>
> RFC 1122 specifies two threshold values R1 and R2 for connection timeouts,
> which may represent a number of allowed retransmissions or a timeout value.
> Currently linux uses sysctl_tcp_retries{1,2} to specify the thresholds
> in number of allowed retransmissions.
>
> For any desired threshold R2 (by means of time) one can specify tcp_retries2
> (by means of number of retransmissions) such that TCP will not time out
> earlier than R2. This is the case, because the RTO schedule follows a fixed
> pattern, namely exponential backoff.
>
> However, the RTO behaviour is not predictable any more if RTO backoffs can
> be
> reverted, as it is the case in the draft
> "Make TCP more Robust to Long Connectivity Disruptions"
> (http://tools.ietf.org/html/draft-zimmermann-tcp-lcd).
>
> In the worst case TCP would time out a connection after 3.2 seconds, if the
> initial RTO equaled MIN_RTO and each backoff has been reverted.
>
> This patch introduces a function retransmits_timed_out(N),
> which calculates the timeout of a TCP connection, assuming an initial
> RTO of MIN_RTO and N unsuccessful, exponentially backed-off retransmissions.
>
> Whenever timeout decisions are made by comparing the retransmission counter
> to some value N, this function can be used, instead.
>
> The meaning of tcp_retries2 will be changed, as many more RTO
> retransmissions
> can occur than the value indicates. However, it yields a timeout which is
> similar to the one of an unpatched, exponentially backing off TCP in the
> same
> scenario. As no application could rely on an RTO greater than MIN_RTO, there
> should be no risk of a regression.
This looks like a typical "fix one problem, introducing a few more" patch :(.
What do you mean by "no application could rely on an RTO greater than
MIN_RTO..."
above? How can you make the assumption that RTO is not too far off
from TCP_RTO_MIN?
While you tried to address a problem where the retransmission count
was high but the actual
timeout duration was too short, have you considered the other case
around, i.e., the timeout
duration is long but the retransmission count is too short? This is
exactly what's happening
to us with your patch. We've much reduced TCP_RTO_MIN for our internal
traffic, but not
noticing your change has severely shortened the R1 & R2 recommended by
RFC1122 for our
long haul traffic until now. In many cases R1 threshold was met upon
the first retrans timeout.
I think retransmits_timed_out() should check against both time
duration and retrans count
(icsk_retransmits).
Thought?
Jerry
>
> Signed-off-by: Damian Lukowski <damian@tvk.rwth-aachen.de>
> ---
> include/net/tcp.h | 18 ++++++++++++++++++
> net/ipv4/tcp_timer.c | 11 +++++++----
> 2 files changed, 25 insertions(+), 4 deletions(-)
>
> diff --git a/include/net/tcp.h b/include/net/tcp.h
> index c35b329..17d1a88 100644
> --- a/include/net/tcp.h
> +++ b/include/net/tcp.h
> @@ -1247,6 +1247,24 @@ static inline struct sk_buff
> *tcp_write_queue_prev(struct sock *sk, struct sk_bu
> #define tcp_for_write_queue_from_safe(skb, tmp, sk) \
> skb_queue_walk_from_safe(&(sk)->sk_write_queue, skb, tmp)
>
> +static inline bool retransmits_timed_out(const struct sock *sk,
> + unsigned int boundary)
> +{
> + int limit, K;
> + if (!inet_csk(sk)->icsk_retransmits)
> + return false;
> +
> + K = ilog2(TCP_RTO_MAX/TCP_RTO_MIN);
> +
> + if (boundary <= K)
> + limit = ((2 << boundary) - 1) * TCP_RTO_MIN;
> + else
> + limit = ((2 << K) - 1) * TCP_RTO_MIN +
> + (boundary - K) * TCP_RTO_MAX;
> +
> + return (tcp_time_stamp - tcp_sk(sk)->retrans_stamp) >= limit;
> +}
> +
> static inline struct sk_buff *tcp_send_head(struct sock *sk)
> {
> return sk->sk_send_head;
> diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
> index a3ba494..2972d7b 100644
> --- a/net/ipv4/tcp_timer.c
> +++ b/net/ipv4/tcp_timer.c
> @@ -137,13 +137,14 @@ static int tcp_write_timeout(struct sock *sk)
> {
> struct inet_connection_sock *icsk = inet_csk(sk);
> int retry_until;
> + bool do_reset;
>
> if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {
> if (icsk->icsk_retransmits)
> dst_negative_advice(&sk->sk_dst_cache);
> retry_until = icsk->icsk_syn_retries ? :
> sysctl_tcp_syn_retries;
> } else {
> - if (icsk->icsk_retransmits >= sysctl_tcp_retries1) {
> + if (retransmits_timed_out(sk, sysctl_tcp_retries1)) {
> /* Black hole detection */
> tcp_mtu_probing(icsk, sk);
>
> @@ -155,13 +156,15 @@ static int tcp_write_timeout(struct sock *sk)
> const int alive = (icsk->icsk_rto < TCP_RTO_MAX);
>
> retry_until = tcp_orphan_retries(sk, alive);
> + do_reset = alive ||
> + !retransmits_timed_out(sk, retry_until);
>
> - if (tcp_out_of_resources(sk, alive ||
> icsk->icsk_retransmits < retry_until))
> + if (tcp_out_of_resources(sk, do_reset))
> return 1;
> }
> }
>
> - if (icsk->icsk_retransmits >= retry_until) {
> + if (retransmits_timed_out(sk, retry_until)) {
> /* Has it gone just too far? */
> tcp_write_err(sk);
> return 1;
> @@ -385,7 +388,7 @@ void tcp_retransmit_timer(struct sock *sk)
> out_reset_timer:
> icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX);
> inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto,
> TCP_RTO_MAX);
> - if (icsk->icsk_retransmits > sysctl_tcp_retries1)
> + if (retransmits_timed_out(sk, sysctl_tcp_retries1 + 1))
> __sk_dst_reset(sk);
>
> out:;
> --
> 1.6.3.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* [PATCH ethtool 0/7] Generic netdev features support
From: Ben Hutchings @ 2012-06-02 0:33 UTC (permalink / raw)
To: netdev; +Cc: Michał Mirosław, Mahesh Bandewar
This series adds support for the not-so-new generic netdev features
ethtool API, along with some test infrastructure and test cases to check
that it works with old and new kernel versions. I'm still not convinced
that there are enough test cases, but I've held this back for too damn
long already.
I'd like to include these changes in an ethtool 3.4 release by the end
of next week, so let me know if there's anything wrong with them.
Ben.
Ben Hutchings (7):
Run tests in-process
Add output file parameter to dump_hex() and make it extern
test: Add test_ioctl() function to support a mock send_ioctl()
Add unit tests for setting offload features (old API)
Regularise offload feature settings
Report when offload feature changes are not exactly as requested
Change -k/-K options to use ETHTOOL_{G,S}FEATURES
.gitignore | 2 +-
Makefile.am | 10 +-
ethtool.8.in | 31 +--
ethtool.c | 668 +++++++++++++++++++++++++++++++++++--------------------
internal.h | 72 ++++++
test-cmdline.c | 14 +-
test-common.c | 357 +++++++++++++++++++++++++++---
test-features.c | 516 ++++++++++++++++++++++++++++++++++++++++++
8 files changed, 1358 insertions(+), 312 deletions(-)
--
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.
^ permalink raw reply
* [PATCH ethtool 1/7] Run tests in-process
From: Ben Hutchings @ 2012-06-02 0:35 UTC (permalink / raw)
To: netdev; +Cc: Michał Mirosław, Mahesh Bandewar
In-Reply-To: <1338597227.2770.13.camel@bwh-desktop.uk.solarflarecom.com>
Wrap main(), exit(), and resource management so that ethtool commands
can be tested without starting a new process and without leaking.
This will allow deeper teesting that covers ioctl requests and
responses.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
.gitignore | 1 -
Makefile.am | 6 +-
ethtool.c | 9 +-
internal.h | 42 ++++++++
test-cmdline.c | 7 ++
test-common.c | 311 ++++++++++++++++++++++++++++++++++++++++++++++++++------
6 files changed, 332 insertions(+), 44 deletions(-)
diff --git a/.gitignore b/.gitignore
index e10c4ef..62bf520 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,7 +13,6 @@ ethtool.spec
ethtool.8
ethtool
test-cmdline
-test-one-cmdline
stamp-h1
config.*
aclocal.m4
diff --git a/Makefile.am b/Makefile.am
index 789cd9a..d1aec43 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -12,11 +12,9 @@ ethtool_SOURCES = ethtool.c ethtool-copy.h internal.h net_tstamp-copy.h \
rxclass.c sfpid.c
TESTS = test-cmdline
-check_PROGRAMS = test-cmdline test-one-cmdline
-test_cmdline_SOURCES = test-cmdline.c test-common.c
+check_PROGRAMS = test-cmdline
+test_cmdline_SOURCES = test-cmdline.c test-common.c $(ethtool_SOURCES)
test_cmdline_CFLAGS = -DTEST_ETHTOOL
-test_one_cmdline_SOURCES = $(ethtool_SOURCES)
-test_one_cmdline_CFLAGS = -DTEST_ETHTOOL
dist-hook:
cp $(top_srcdir)/ethtool.spec $(distdir)
diff --git a/ethtool.c b/ethtool.c
index f18f611..65bdd38 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -3261,16 +3261,13 @@ static int do_getmodule(struct cmd_context *ctx)
return 0;
}
+#ifndef TEST_ETHTOOL
int send_ioctl(struct cmd_context *ctx, void *cmd)
{
-#ifndef TEST_ETHTOOL
ctx->ifr.ifr_data = cmd;
return ioctl(ctx->fd, SIOCETHTOOL, &ctx->ifr);
-#else
- /* If we get this far then parsing succeeded */
- exit(0);
-#endif
}
+#endif
static int show_usage(struct cmd_context *ctx);
@@ -3451,7 +3448,7 @@ static int show_usage(struct cmd_context *ctx)
return 0;
}
-int main(int argc, char **argp, char **envp)
+int main(int argc, char **argp)
{
int (*func)(struct cmd_context *);
int want_device;
diff --git a/internal.h b/internal.h
index 55f0d8a..10abe25 100644
--- a/internal.h
+++ b/internal.h
@@ -6,7 +6,11 @@
#ifdef HAVE_CONFIG_H
#include "ethtool-config.h"
#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/types.h>
+#include <unistd.h>
#include <endian.h>
#include <sys/ioctl.h>
#include <net/if.h>
@@ -98,6 +102,44 @@ struct cmd_context {
#ifdef TEST_ETHTOOL
int test_cmdline(const char *args);
+
+#ifndef TEST_NO_WRAPPERS
+int test_main(int argc, char **argp);
+#define main(...) test_main(__VA_ARGS__)
+void test_exit(int rc) __attribute__((noreturn));
+#undef exit
+#define exit(rc) test_exit(rc)
+void *test_malloc(size_t size);
+#undef malloc
+#define malloc(size) test_malloc(size)
+void *test_calloc(size_t nmemb, size_t size);
+#undef calloc
+#define calloc(nmemb, size) test_calloc(nmemb, size)
+char *test_strdup(const char *s);
+#undef strdup
+#define strdup(s) test_strdup(s)
+void *test_free(void *ptr);
+#undef free
+#define free(ptr) test_free(ptr)
+void *test_realloc(void *ptr, size_t size);
+#undef realloc
+#define realloc(ptr, size) test_realloc(ptr, size)
+int test_open(const char *pathname, int flag, ...);
+#undef open
+#define open(...) test_open(__VA_ARGS__)
+int test_socket(int domain, int type, int protocol);
+#undef socket
+#define socket(...) test_socket(__VA_ARGS__)
+int test_close(int fd);
+#undef close
+#define close(fd) test_close(fd)
+FILE *test_fopen(const char *path, const char *mode);
+#undef fopen
+#define fopen(path, mode) test_fopen(path, mode)
+int test_fclose(FILE *fh);
+#undef fclose
+#define fclose(fh) test_fclose(fh)
+#endif
#endif
int send_ioctl(struct cmd_context *ctx, void *cmd);
diff --git a/test-cmdline.c b/test-cmdline.c
index c30b0e6..c62bb97 100644
--- a/test-cmdline.c
+++ b/test-cmdline.c
@@ -9,6 +9,7 @@
#include <stdio.h>
#include <stdlib.h>
+#define TEST_NO_WRAPPERS
#include "internal.h"
static struct test_case {
@@ -232,6 +233,12 @@ static struct test_case {
{ 1, "-0" },
};
+int send_ioctl(struct cmd_context *ctx, void *cmd)
+{
+ /* If we get this far then parsing succeeded */
+ test_exit(0);
+}
+
int main(void)
{
struct test_case *tc;
diff --git a/test-common.c b/test-common.c
index 4ea84c8..69853aa 100644
--- a/test-common.c
+++ b/test-common.c
@@ -2,27 +2,268 @@
* Common test functions for ethtool
* Copyright 2011 Solarflare Communications Inc.
*
+ * Partly derived from kernel <linux/list.h>.
+ *
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
+#include <assert.h>
+#include <setjmp.h>
+#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <sys/fcntl.h>
-#include <sys/wait.h>
#include <unistd.h>
+#define TEST_NO_WRAPPERS
#include "internal.h"
+/* List utilities */
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+static void init_list_head(struct list_head *list)
+{
+ list->next = list;
+ list->prev = list;
+}
+
+static void list_add(struct list_head *new, struct list_head *head)
+{
+ head->next->prev = new;
+ new->next = head->next;
+ new->prev = head;
+ head->next = new;
+}
+
+static void list_del(struct list_head *entry)
+{
+ entry->next->prev = entry->prev;
+ entry->prev->next = entry->next;
+ entry->next = NULL;
+ entry->prev = NULL;
+}
+
+#define list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+/* Free memory at end of test */
+
+static struct list_head malloc_list = LIST_HEAD_INIT(malloc_list);
+
+void *test_malloc(size_t size)
+{
+ struct list_head *block = malloc(sizeof(*block) + size);
+
+ if (!block)
+ return NULL;
+ list_add(block, &malloc_list);
+ return block + 1;
+}
+
+void *test_calloc(size_t nmemb, size_t size)
+{
+ void *ptr = test_malloc(nmemb * size);
+
+ if (ptr)
+ memset(ptr, 0, nmemb * size);
+ return ptr;
+}
+
+char *test_strdup(const char *s)
+{
+ size_t size = strlen(s) + 1;
+ char *dup = test_malloc(size);
+
+ if (dup)
+ memcpy(dup, s, size);
+ return dup;
+}
+
+void test_free(void *ptr)
+{
+ struct list_head *block;
+
+ if (!ptr)
+ return;
+ block = (struct list_head *)ptr - 1;
+ list_del(block);
+ free(block);
+}
+
+void *test_realloc(void *ptr, size_t size)
+{
+ struct list_head *block;
+
+ if (ptr) {
+ block = (struct list_head *)ptr - 1;
+ list_del(block);
+ }
+ block = realloc(block, sizeof(*block) + size);
+ if (!block)
+ return NULL;
+ list_add(block, &malloc_list);
+ return block + 1;
+}
+
+static void test_free_all(void)
+{
+ struct list_head *block, *next;
+
+ list_for_each_safe(block, next, &malloc_list)
+ free(block);
+ init_list_head(&malloc_list);
+}
+
+/* Close files at end of test */
+
+struct file_node {
+ struct list_head link;
+ FILE *fh;
+ int fd;
+};
+
+static struct list_head file_list = LIST_HEAD_INIT(file_list);
+
+int test_open(const char *pathname, int flag, ...)
+{
+ struct file_node *node;
+ mode_t mode;
+
+ if (flag & O_CREAT) {
+ va_list ap;
+ va_start(ap, flag);
+ mode = va_arg(ap, mode_t);
+ va_end(ap);
+ } else {
+ mode = 0;
+ }
+
+ node = malloc(sizeof(*node));
+ if (!node)
+ return -1;
+
+ node->fd = open(pathname, flag, mode);
+ if (node->fd < 0) {
+ free(node);
+ return -1;
+ }
+
+ node->fh = NULL;
+ list_add(&node->link, &file_list);
+ return node->fd;
+}
+
+int test_socket(int domain, int type, int protocol)
+{
+ struct file_node *node;
+
+ node = malloc(sizeof(*node));
+ if (!node)
+ return -1;
+
+ node->fd = socket(domain, type, protocol);
+ if (node->fd < 0) {
+ free(node);
+ return -1;
+ }
+
+ node->fh = NULL;
+ list_add(&node->link, &file_list);
+ return node->fd;
+}
+
+int test_close(int fd)
+{
+ struct list_head *head, *next;
+
+ if (fd >= 0) {
+ list_for_each_safe(head, next, &file_list) {
+ if (((struct file_node *)head)->fd == fd) {
+ list_del(head);
+ free(head);
+ break;
+ }
+ }
+ }
+
+ return close(fd);
+}
+
+FILE *test_fopen(const char *path, const char *mode)
+{
+ struct file_node *node;
+
+ node = malloc(sizeof(*node));
+ if (!node)
+ return NULL;
+
+ node->fh = fopen(path, mode);
+ if (!node->fh) {
+ free(node);
+ return NULL;
+ }
+
+ node->fd = -1;
+ list_add(&node->link, &file_list);
+ return node->fh;
+}
+
+int test_fclose(FILE *fh)
+{
+ struct list_head *head, *next;
+
+ assert(fh);
+
+ list_for_each_safe(head, next, &file_list) {
+ if (((struct file_node *)head)->fh == fh) {
+ list_del(head);
+ free(head);
+ break;
+ }
+ }
+
+ return fclose(fh);
+}
+
+static void test_close_all(void)
+{
+ struct list_head *head, *next;
+ struct file_node *node;
+
+ list_for_each_safe(head, next, &file_list) {
+ node = (struct file_node *)head;
+ if (node->fh)
+ fclose(node->fh);
+ else
+ close(node->fd);
+ free(node);
+ }
+ init_list_head(&file_list);
+}
+
+/* Wrap test main function */
+
+static jmp_buf test_return;
+
+void test_exit(int rc)
+{
+ longjmp(test_return, rc + 1);
+}
+
int test_cmdline(const char *args)
{
int argc, i;
char **argv;
const char *arg;
size_t len;
- pid_t pid;
- int dev_null;
- int status;
+ int dev_null = -1, old_stdout = -1, old_stderr = -1;
int rc;
/* Convert line to argv */
@@ -37,12 +278,12 @@ int test_cmdline(const char *args)
break;
arg += len + 1;
}
- argv = calloc(argc + 1, sizeof(argv[0]));
- argv[0] = strdup("ethtool");
+ argv = test_calloc(argc + 1, sizeof(argv[0]));
+ argv[0] = test_strdup("ethtool");
arg = args;
for (i = 1; i < argc; i++) {
len = strcspn(arg, " ");
- argv[i] = malloc(len + 1);
+ argv[i] = test_malloc(len + 1);
memcpy(argv[i], arg, len);
argv[i][len] = 0;
arg += len + 1;
@@ -56,37 +297,41 @@ int test_cmdline(const char *args)
}
fflush(NULL);
- pid = fork();
-
- /* Child */
- if (pid == 0) {
- dup2(dev_null, STDIN_FILENO);
- if (!getenv("ETHTOOL_TEST_VERBOSE")) {
- dup2(dev_null, STDOUT_FILENO);
- dup2(dev_null, STDERR_FILENO);
+ dup2(dev_null, STDIN_FILENO);
+ if (!getenv("TEST_TEST_VERBOSE")) {
+ old_stdout = dup(STDOUT_FILENO);
+ if (old_stdout < 0) {
+ perror("dup stdout");
+ rc = -1;
+ goto out;
}
- execv("./test-one-cmdline", argv);
- _exit(126);
+ dup2(dev_null, STDOUT_FILENO);
+ old_stderr = dup(STDERR_FILENO);
+ if (old_stderr < 0) {
+ perror("dup stderr");
+ rc = -1;
+ goto out;
+ }
+ dup2(dev_null, STDERR_FILENO);
}
- /* Parent */
- if (pid < 0) {
- perror("fork");
- close(dev_null);
- rc = -1;
- goto out;
+ rc = setjmp(test_return);
+ rc = rc ? rc - 1 : test_main(argc, argv);
+
+out:
+ fflush(NULL);
+ if (old_stderr >= 0) {
+ dup2(old_stderr, STDERR_FILENO);
+ close(old_stderr);
}
- close(dev_null);
- if (waitpid(pid, &status, 0) < 0) {
- perror("waitpid");
- rc = -1;
- goto out;
+ if (old_stdout >= 0) {
+ dup2(old_stdout, STDOUT_FILENO);
+ close(old_stdout);
}
- rc = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
+ if (dev_null >= 0)
+ close(dev_null);
-out:
- for (i = 0; i < argc; i++)
- free(argv[i]);
- free(argv);
+ test_free_all();
+ test_close_all();
return rc;
}
--
1.7.7.6
--
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.
^ permalink raw reply related
* [PATCH ethtool 2/7] Add output file parameter to dump_hex() and make it extern
From: Ben Hutchings @ 2012-06-02 0:36 UTC (permalink / raw)
To: netdev; +Cc: Michał Mirosław, Mahesh Bandewar
In-Reply-To: <1338597227.2770.13.camel@bwh-desktop.uk.solarflarecom.com>
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
ethtool.c | 19 ++++++++++---------
internal.h | 2 ++
2 files changed, 12 insertions(+), 9 deletions(-)
diff --git a/ethtool.c b/ethtool.c
index 65bdd38..9d42ca8 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -787,18 +787,18 @@ static const struct {
{ "st_gmac", st_gmac_dump_regs },
};
-static void dump_hex(__u8 *data, int len, int offset)
+void dump_hex(FILE *file, const u8 *data, int len, int offset)
{
int i;
- fprintf(stdout, "Offset\t\tValues\n");
- fprintf(stdout, "------\t\t------");
+ fprintf(file, "Offset\t\tValues\n");
+ fprintf(file, "------\t\t------");
for (i = 0; i < len; i++) {
if (i % 16 == 0)
- fprintf(stdout, "\n0x%04x:\t\t", i + offset);
- fprintf(stdout, "%02x ", data[i]);
+ fprintf(file, "\n0x%04x:\t\t", i + offset);
+ fprintf(file, "%02x ", data[i]);
}
- fprintf(stdout, "\n");
+ fprintf(file, "\n");
}
static int dump_regs(int gregs_dump_raw, int gregs_dump_hex,
@@ -834,7 +834,7 @@ static int dump_regs(int gregs_dump_raw, int gregs_dump_hex,
ETHTOOL_BUSINFO_LEN))
return driver_list[i].func(info, regs);
- dump_hex(regs->data, regs->len, 0);
+ dump_hex(stdout, regs->data, regs->len, 0);
return 0;
}
@@ -853,7 +853,7 @@ static int dump_eeprom(int geeprom_dump_raw, struct ethtool_drvinfo *info,
return tg3_dump_eeprom(info, ee);
}
- dump_hex(ee->data, ee->len, ee->offset);
+ dump_hex(stdout, ee->data, ee->len, ee->offset);
return 0;
}
@@ -3253,7 +3253,8 @@ static int do_getmodule(struct cmd_context *ctx)
}
}
if (geeprom_dump_hex)
- dump_hex(eeprom->data, eeprom->len, eeprom->offset);
+ dump_hex(stdout, eeprom->data,
+ eeprom->len, eeprom->offset);
}
free(eeprom);
diff --git a/internal.h b/internal.h
index 10abe25..b013783 100644
--- a/internal.h
+++ b/internal.h
@@ -144,6 +144,8 @@ int test_fclose(FILE *fh);
int send_ioctl(struct cmd_context *ctx, void *cmd);
+void dump_hex(FILE *f, const u8 *data, int len, int offset);
+
/* National Semiconductor DP83815, DP83816 */
int natsemi_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
int natsemi_dump_eeprom(struct ethtool_drvinfo *info,
--
1.7.7.6
--
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.
^ permalink raw reply related
* [PATCH ethtool 3/7] test: Add test_ioctl() function to support a mock send_ioctl()
From: Ben Hutchings @ 2012-06-02 0:37 UTC (permalink / raw)
To: netdev; +Cc: Michał Mirosław, Mahesh Bandewar
In-Reply-To: <1338597227.2770.13.camel@bwh-desktop.uk.solarflarecom.com>
test_ioctl() verifies an ethtool ioctl structure and either returns a
canned response (if it was as expected) or aborts the test.
Adjust the file redirection in test_cmdline() so that test_ioctl() can
always print error messages.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
internal.h | 10 ++++++++
test-common.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++---------
2 files changed, 68 insertions(+), 12 deletions(-)
diff --git a/internal.h b/internal.h
index b013783..0fff2a5 100644
--- a/internal.h
+++ b/internal.h
@@ -103,6 +103,16 @@ struct cmd_context {
#ifdef TEST_ETHTOOL
int test_cmdline(const char *args);
+struct cmd_expect {
+ const void *cmd; /* expected command; NULL at end of list */
+ size_t cmd_len; /* length to match (might be < sizeof struct) */
+ int rc; /* kernel return code */
+ const void *resp; /* response to write back; may be NULL */
+ size_t resp_len; /* length to write back */
+};
+int test_ioctl(const struct cmd_expect *expect, void *cmd);
+#define TEST_IOCTL_MISMATCH (-2)
+
#ifndef TEST_NO_WRAPPERS
int test_main(int argc, char **argp);
#define main(...) test_main(__VA_ARGS__)
diff --git a/test-common.c b/test-common.c
index 69853aa..adc3cd4 100644
--- a/test-common.c
+++ b/test-common.c
@@ -10,6 +10,7 @@
*/
#include <assert.h>
+#include <errno.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stdlib.h>
@@ -251,19 +252,52 @@ static void test_close_all(void)
/* Wrap test main function */
static jmp_buf test_return;
+static FILE *orig_stderr;
void test_exit(int rc)
{
longjmp(test_return, rc + 1);
}
+int test_ioctl(const struct cmd_expect *expect, void *cmd)
+{
+ int rc;
+
+ if (!expect->cmd || *(u32 *)cmd != *(const u32 *)expect->cmd) {
+ /* We have no idea how long this command structure is */
+ fprintf(orig_stderr, "Unexpected ioctl: cmd=%#10x\n",
+ *(u32 *)cmd);
+ return TEST_IOCTL_MISMATCH;
+ }
+
+ if (memcmp(cmd, expect->cmd, expect->cmd_len)) {
+ fprintf(orig_stderr, "Expected ioctl structure:\n");
+ dump_hex(orig_stderr, expect->cmd, expect->cmd_len, 0);
+ fprintf(orig_stderr, "Actual ioctl structure:\n");
+ dump_hex(orig_stderr, cmd, expect->cmd_len, 0);
+ return TEST_IOCTL_MISMATCH;
+ }
+
+ if (expect->resp)
+ memcpy(cmd, expect->resp, expect->resp_len);
+ rc = expect->rc;
+
+ /* Convert kernel return code according to libc convention */
+ if (rc >= 0) {
+ return rc;
+ } else {
+ errno = -rc;
+ return -1;
+ }
+}
+
int test_cmdline(const char *args)
{
int argc, i;
char **argv;
const char *arg;
size_t len;
- int dev_null = -1, old_stdout = -1, old_stderr = -1;
+ int dev_null = -1, orig_stdout_fd = -1, orig_stderr_fd = -1;
int rc;
/* Convert line to argv */
@@ -298,20 +332,28 @@ int test_cmdline(const char *args)
fflush(NULL);
dup2(dev_null, STDIN_FILENO);
- if (!getenv("TEST_TEST_VERBOSE")) {
- old_stdout = dup(STDOUT_FILENO);
- if (old_stdout < 0) {
+ if (getenv("TEST_TEST_VERBOSE")) {
+ orig_stderr = stderr;
+ } else {
+ orig_stdout_fd = dup(STDOUT_FILENO);
+ if (orig_stdout_fd < 0) {
perror("dup stdout");
rc = -1;
goto out;
}
dup2(dev_null, STDOUT_FILENO);
- old_stderr = dup(STDERR_FILENO);
- if (old_stderr < 0) {
+ orig_stderr_fd = dup(STDERR_FILENO);
+ if (orig_stderr_fd < 0) {
perror("dup stderr");
rc = -1;
goto out;
}
+ orig_stderr = fdopen(orig_stderr_fd, "w");
+ if (orig_stderr == NULL) {
+ perror("fdopen orig_stderr_fd");
+ rc = -1;
+ goto out;
+ }
dup2(dev_null, STDERR_FILENO);
}
@@ -320,13 +362,17 @@ int test_cmdline(const char *args)
out:
fflush(NULL);
- if (old_stderr >= 0) {
- dup2(old_stderr, STDERR_FILENO);
- close(old_stderr);
+ if (orig_stderr_fd >= 0) {
+ dup2(orig_stderr_fd, STDERR_FILENO);
+ if (orig_stderr)
+ fclose(orig_stderr);
+ else
+ close(orig_stderr_fd);
}
- if (old_stdout >= 0) {
- dup2(old_stdout, STDOUT_FILENO);
- close(old_stdout);
+ orig_stderr = NULL;
+ if (orig_stdout_fd >= 0) {
+ dup2(orig_stdout_fd, STDOUT_FILENO);
+ close(orig_stdout_fd);
}
if (dev_null >= 0)
close(dev_null);
--
1.7.7.6
--
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.
^ permalink raw reply related
* [PATCH ethtool 4/7] Add unit tests for setting offload features (old API)
From: Ben Hutchings @ 2012-06-02 0:37 UTC (permalink / raw)
To: netdev; +Cc: Michał Mirosław, Mahesh Bandewar
In-Reply-To: <1338597227.2770.13.camel@bwh-desktop.uk.solarflarecom.com>
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
.gitignore | 1 +
Makefile.am | 6 ++-
test-features.c | 153 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 158 insertions(+), 2 deletions(-)
create mode 100644 test-features.c
diff --git a/.gitignore b/.gitignore
index 62bf520..45c9501 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,6 +13,7 @@ ethtool.spec
ethtool.8
ethtool
test-cmdline
+test-features
stamp-h1
config.*
aclocal.m4
diff --git a/Makefile.am b/Makefile.am
index d1aec43..1b96b98 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -11,10 +11,12 @@ ethtool_SOURCES = ethtool.c ethtool-copy.h internal.h net_tstamp-copy.h \
smsc911x.c at76c50x-usb.c sfc.c stmmac.c \
rxclass.c sfpid.c
-TESTS = test-cmdline
-check_PROGRAMS = test-cmdline
+TESTS = test-cmdline test-features
+check_PROGRAMS = test-cmdline test-features
test_cmdline_SOURCES = test-cmdline.c test-common.c $(ethtool_SOURCES)
test_cmdline_CFLAGS = -DTEST_ETHTOOL
+test_features_SOURCES = test-features.c test-common.c $(ethtool_SOURCES)
+test_features_CFLAGS = -DTEST_ETHTOOL
dist-hook:
cp $(top_srcdir)/ethtool.spec $(distdir)
diff --git a/test-features.c b/test-features.c
new file mode 100644
index 0000000..4d8680a
--- /dev/null
+++ b/test-features.c
@@ -0,0 +1,153 @@
+/****************************************************************************
+ * Test cases for ethtool features
+ * Copyright 2012 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define TEST_NO_WRAPPERS
+#include "internal.h"
+
+static const struct ethtool_value
+cmd_grxcsum_off = { ETHTOOL_GRXCSUM, 0 },
+cmd_grxcsum_on = { ETHTOOL_GRXCSUM, 1 },
+cmd_srxcsum_off = { ETHTOOL_SRXCSUM, 0 },
+cmd_srxcsum_on = { ETHTOOL_SRXCSUM, 1 },
+cmd_gtxcsum_off = { ETHTOOL_GTXCSUM, 0 },
+cmd_gtxcsum_on = { ETHTOOL_GTXCSUM, 1 },
+cmd_stxcsum_off = { ETHTOOL_STXCSUM, 0 },
+cmd_stxcsum_on = { ETHTOOL_STXCSUM, 1 },
+cmd_gsg_off = { ETHTOOL_GSG, 0 },
+cmd_gsg_on = { ETHTOOL_GSG, 1 },
+cmd_ssg_off = { ETHTOOL_SSG, 0 },
+cmd_ssg_on = { ETHTOOL_SSG, 1 },
+cmd_gtso_off = { ETHTOOL_GTSO, 0 },
+cmd_gtso_on = { ETHTOOL_GTSO, 1 },
+cmd_stso_off = { ETHTOOL_STSO, 0 },
+cmd_stso_on = { ETHTOOL_STSO, 1 },
+cmd_gufo_off = { ETHTOOL_GUFO, 0 },
+cmd_gufo_on = { ETHTOOL_GUFO, 1 },
+cmd_sufo_off = { ETHTOOL_SUFO, 0 },
+cmd_sufo_on = { ETHTOOL_SUFO, 1 },
+cmd_ggso_off = { ETHTOOL_GGSO, 0 },
+cmd_ggso_on = { ETHTOOL_GGSO, 1 },
+cmd_sgso_off = { ETHTOOL_SGSO, 0 },
+cmd_sgso_on = { ETHTOOL_SGSO, 1 },
+cmd_ggro_off = { ETHTOOL_GGRO, 0 },
+cmd_ggro_on = { ETHTOOL_GGRO, 1 },
+cmd_sgro_off = { ETHTOOL_SGRO, 0 },
+cmd_sgro_on = { ETHTOOL_SGRO, 1 },
+cmd_gflags_off = { ETHTOOL_GFLAGS, 0 },
+cmd_gflags_on = { ETHTOOL_GFLAGS,
+ ETH_FLAG_LRO | ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN |
+ ETH_FLAG_NTUPLE | ETH_FLAG_RXHASH },
+cmd_sflags_off = { ETHTOOL_SFLAGS, 0 },
+cmd_sflags_ntuple = { ETHTOOL_GFLAGS, ETH_FLAG_NTUPLE },
+cmd_sflags_on = { ETHTOOL_SFLAGS,
+ ETH_FLAG_LRO | ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN |
+ ETH_FLAG_NTUPLE | ETH_FLAG_RXHASH },
+cmd_sflags_not_rxhash = { ETHTOOL_SFLAGS,
+ ETH_FLAG_LRO | ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN |
+ ETH_FLAG_NTUPLE };
+
+static const struct cmd_expect cmd_expect_get_features_off[] = {
+ { &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
+ { &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
+ { &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
+ { &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
+ { &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
+ { &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
+ { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
+ { &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
+ { 0, 0, 0, 0, 0 }
+};
+
+static const struct cmd_expect cmd_expect_set_features_off[] = {
+ { &cmd_srxcsum_off, sizeof(cmd_srxcsum_off), 0, 0, 0 },
+ { &cmd_stxcsum_off, sizeof(cmd_stxcsum_off), 0, 0, 0 },
+ { &cmd_ssg_off, sizeof(cmd_ssg_off), 0, 0, 0 },
+ { &cmd_stso_off, sizeof(cmd_stso_off), 0, 0, 0 },
+ { &cmd_sufo_off, sizeof(cmd_sufo_off), 0, 0, 0 },
+ { &cmd_sgso_off, sizeof(cmd_sgso_off), 0, 0, 0 },
+ { &cmd_gflags_on, 4, 0, &cmd_gflags_on, sizeof(cmd_sflags_on) },
+ { &cmd_sflags_off, sizeof(cmd_sflags_off), 0, 0, 0 },
+ { &cmd_sgro_off, sizeof(cmd_sgro_off), 0, 0, 0 },
+ { 0, 0, 0, 0, 0 }
+};
+
+static const struct cmd_expect cmd_expect_set_features_on[] = {
+ { &cmd_srxcsum_on, sizeof(cmd_srxcsum_on), 0, 0, 0 },
+ { &cmd_stxcsum_on, sizeof(cmd_stxcsum_on), 0, 0, 0 },
+ { &cmd_ssg_on, sizeof(cmd_ssg_on), 0, 0, 0 },
+ { &cmd_stso_on, sizeof(cmd_stso_on), 0, 0, 0 },
+ { &cmd_sufo_on, sizeof(cmd_sufo_on), 0, 0, 0 },
+ { &cmd_sgso_on, sizeof(cmd_sgso_on), 0, 0, 0 },
+ { &cmd_gflags_off, 4, 0, &cmd_gflags_on, sizeof(cmd_sflags_off) },
+ { &cmd_sflags_on, sizeof(cmd_sflags_on), 0, 0, 0 },
+ { &cmd_sgro_on, sizeof(cmd_sgro_on), 0, 0, 0 },
+ { 0, 0, 0, 0, 0 }
+};
+
+static struct test_case {
+ int rc;
+ const char *args;
+ const struct cmd_expect *expect;
+} const test_cases[] = {
+ { 0, "-k devname", cmd_expect_get_features_off },
+ { 0, "-K devname rx off tx off sg off tso off ufo off gso off lro off rxvlan off txvlan off ntuple off rxhash off gro off",
+ cmd_expect_set_features_off },
+ { 0, "-K devname rx on tx on sg on tso on ufo on gso on lro on rxvlan on txvlan on ntuple on rxhash on gro on",
+ cmd_expect_set_features_on },
+};
+
+static int expect_matched;
+static const struct cmd_expect *expect_next;
+
+int send_ioctl(struct cmd_context *ctx, void *cmd)
+{
+ int rc = test_ioctl(expect_next, cmd);
+
+ if (rc == TEST_IOCTL_MISMATCH) {
+ expect_matched = 0;
+ test_exit(0);
+ }
+ expect_next++;
+ return rc;
+}
+
+int main(void)
+{
+ const struct test_case *tc;
+ int test_rc;
+ int rc = 0;
+
+ for (tc = test_cases; tc < test_cases + ARRAY_SIZE(test_cases); tc++) {
+ if (getenv("ETHTOOL_TEST_VERBOSE"))
+ printf("I: Test command line: ethtool %s\n", tc->args);
+ expect_matched = 1;
+ expect_next = tc->expect;
+ test_rc = test_cmdline(tc->args);
+
+ /* If we found a mismatch, or there is still another
+ * expected ioctl to match, the test failed.
+ */
+ if (!expect_matched || expect_next->cmd) {
+ fprintf(stderr,
+ "E: ethtool %s deviated from the expected "
+ "ioctl sequence after %zu calls\n",
+ tc->args, expect_next - tc->expect);
+ rc = 1;
+ } else if (test_rc != tc->rc) {
+ fprintf(stderr, "E: ethtool %s returns %d\n",
+ tc->args, test_rc);
+ rc = 1;
+ }
+ }
+
+ return rc;
+}
--
1.7.7.6
--
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.
^ permalink raw reply related
* [PATCH ethtool 5/7] Regularise offload feature settings
From: Ben Hutchings @ 2012-06-02 0:38 UTC (permalink / raw)
To: netdev; +Cc: Michał Mirosław, Mahesh Bandewar
In-Reply-To: <1338597227.2770.13.camel@bwh-desktop.uk.solarflarecom.com>
This is partly preparation for use of the new net device features API,
but is useful in its own right.
Replace repetitive code for getting/setting offload flags with data-
driven loops.
This changes error messages to use the same long names for offload
flags as in dump_offload(), and changes various exit codes to 1.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
ethtool.c | 291 +++++++++++++++++--------------------------------------
internal.h | 18 ++++
test-features.c | 6 +-
3 files changed, 110 insertions(+), 205 deletions(-)
diff --git a/ethtool.c b/ethtool.c
index 9d42ca8..34d8b90 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -128,6 +128,38 @@ static const struct flag_info flags_msglvl[] = {
{ "wol", NETIF_MSG_WOL },
};
+static const struct {
+ const char *short_name;
+ const char *long_name;
+ u32 get_cmd, set_cmd;
+ u32 value;
+} off_flag_def[] = {
+ { "rx", "rx-checksumming",
+ ETHTOOL_GRXCSUM, ETHTOOL_SRXCSUM, ETH_FLAG_RXCSUM },
+ { "tx", "tx-checksumming",
+ ETHTOOL_GTXCSUM, ETHTOOL_STXCSUM, ETH_FLAG_TXCSUM },
+ { "sg", "scatter-gather",
+ ETHTOOL_GSG, ETHTOOL_SSG, ETH_FLAG_SG },
+ { "tso", "tcp-segmentation-offload",
+ ETHTOOL_GTSO, ETHTOOL_STSO, ETH_FLAG_TSO },
+ { "ufo", "udp-fragmentation-offload",
+ ETHTOOL_GUFO, ETHTOOL_SUFO, ETH_FLAG_UFO },
+ { "gso", "generic-segmentation-offload",
+ ETHTOOL_GGSO, ETHTOOL_SGSO, ETH_FLAG_GSO },
+ { "gro", "generic-receive-offload",
+ ETHTOOL_GGRO, ETHTOOL_SGRO, ETH_FLAG_GRO },
+ { "lro", "large-receive-offload",
+ 0, 0, ETH_FLAG_LRO },
+ { "rxvlan", "rx-vlan-offload",
+ 0, 0, ETH_FLAG_RXVLAN },
+ { "txvlan", "tx-vlan-offload",
+ 0, 0, ETH_FLAG_TXVLAN },
+ { "ntuple", "ntuple-filters",
+ 0, 0, ETH_FLAG_NTUPLE },
+ { "rxhash", "receive-hashing",
+ 0, 0, ETH_FLAG_RXHASH },
+};
+
static long long
get_int_range(char *str, int base, long long min, long long max)
{
@@ -1037,35 +1069,17 @@ static int dump_coalesce(const struct ethtool_coalesce *ecoal)
return 0;
}
-static int dump_offload(int rx, int tx, int sg, int tso, int ufo, int gso,
- int gro, int lro, int rxvlan, int txvlan, int ntuple,
- int rxhash)
+static int dump_offload(u32 active)
{
- fprintf(stdout,
- "rx-checksumming: %s\n"
- "tx-checksumming: %s\n"
- "scatter-gather: %s\n"
- "tcp-segmentation-offload: %s\n"
- "udp-fragmentation-offload: %s\n"
- "generic-segmentation-offload: %s\n"
- "generic-receive-offload: %s\n"
- "large-receive-offload: %s\n"
- "rx-vlan-offload: %s\n"
- "tx-vlan-offload: %s\n"
- "ntuple-filters: %s\n"
- "receive-hashing: %s\n",
- rx ? "on" : "off",
- tx ? "on" : "off",
- sg ? "on" : "off",
- tso ? "on" : "off",
- ufo ? "on" : "off",
- gso ? "on" : "off",
- gro ? "on" : "off",
- lro ? "on" : "off",
- rxvlan ? "on" : "off",
- txvlan ? "on" : "off",
- ntuple ? "on" : "off",
- rxhash ? "on" : "off");
+ u32 value;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(off_flag_def); i++) {
+ value = off_flag_def[i].value;
+ printf("%s: %s\n",
+ off_flag_def[i].long_name,
+ (active & value) ? "on" : "off");
+ }
return 0;
}
@@ -1636,67 +1650,30 @@ static int do_scoalesce(struct cmd_context *ctx)
static int do_goffload(struct cmd_context *ctx)
{
struct ethtool_value eval;
- int err, allfail = 1, rx = 0, tx = 0, sg = 0;
- int tso = 0, ufo = 0, gso = 0, gro = 0, lro = 0, rxvlan = 0, txvlan = 0,
- ntuple = 0, rxhash = 0;
+ int err, allfail = 1;
+ u32 flags = 0, value;
+ int i;
if (ctx->argc != 0)
exit_bad_args();
fprintf(stdout, "Offload parameters for %s:\n", ctx->devname);
- eval.cmd = ETHTOOL_GRXCSUM;
- err = send_ioctl(ctx, &eval);
- if (err)
- perror("Cannot get device rx csum settings");
- else {
- rx = eval.data;
- allfail = 0;
- }
-
- eval.cmd = ETHTOOL_GTXCSUM;
- err = send_ioctl(ctx, &eval);
- if (err)
- perror("Cannot get device tx csum settings");
- else {
- tx = eval.data;
- allfail = 0;
- }
-
- eval.cmd = ETHTOOL_GSG;
- err = send_ioctl(ctx, &eval);
- if (err)
- perror("Cannot get device scatter-gather settings");
- else {
- sg = eval.data;
- allfail = 0;
- }
-
- eval.cmd = ETHTOOL_GTSO;
- err = send_ioctl(ctx, &eval);
- if (err)
- perror("Cannot get device tcp segmentation offload settings");
- else {
- tso = eval.data;
- allfail = 0;
- }
-
- eval.cmd = ETHTOOL_GUFO;
- err = send_ioctl(ctx, &eval);
- if (err)
- perror("Cannot get device udp large send offload settings");
- else {
- ufo = eval.data;
- allfail = 0;
- }
-
- eval.cmd = ETHTOOL_GGSO;
- err = send_ioctl(ctx, &eval);
- if (err)
- perror("Cannot get device generic segmentation offload settings");
- else {
- gso = eval.data;
- allfail = 0;
+ for (i = 0; i < ARRAY_SIZE(off_flag_def); i++) {
+ value = off_flag_def[i].value;
+ if (!off_flag_def[i].get_cmd)
+ continue;
+ eval.cmd = off_flag_def[i].get_cmd;
+ err = send_ioctl(ctx, &eval);
+ if (err) {
+ fprintf(stderr,
+ "Cannot get device %s settings: %m\n",
+ off_flag_def[i].long_name);
+ } else {
+ if (eval.data)
+ flags |= value;
+ allfail = 0;
+ }
}
eval.cmd = ETHTOOL_GFLAGS;
@@ -1704,20 +1681,7 @@ static int do_goffload(struct cmd_context *ctx)
if (err) {
perror("Cannot get device flags");
} else {
- lro = (eval.data & ETH_FLAG_LRO) != 0;
- rxvlan = (eval.data & ETH_FLAG_RXVLAN) != 0;
- txvlan = (eval.data & ETH_FLAG_TXVLAN) != 0;
- ntuple = (eval.data & ETH_FLAG_NTUPLE) != 0;
- rxhash = (eval.data & ETH_FLAG_RXHASH) != 0;
- allfail = 0;
- }
-
- eval.cmd = ETHTOOL_GGRO;
- err = send_ioctl(ctx, &eval);
- if (err)
- perror("Cannot get device GRO settings");
- else {
- gro = eval.data;
+ flags |= eval.data & ETH_FLAG_EXT_MASK;
allfail = 0;
}
@@ -1726,112 +1690,45 @@ static int do_goffload(struct cmd_context *ctx)
return 83;
}
- return dump_offload(rx, tx, sg, tso, ufo, gso, gro, lro, rxvlan, txvlan,
- ntuple, rxhash);
+ return dump_offload(flags);
}
static int do_soffload(struct cmd_context *ctx)
{
int goffload_changed = 0;
- int off_csum_rx_wanted = -1;
- int off_csum_tx_wanted = -1;
- int off_sg_wanted = -1;
- int off_tso_wanted = -1;
- int off_ufo_wanted = -1;
- int off_gso_wanted = -1;
u32 off_flags_wanted = 0;
u32 off_flags_mask = 0;
- int off_gro_wanted = -1;
- struct cmdline_info cmdline_offload[] = {
- { "rx", CMDL_BOOL, &off_csum_rx_wanted, NULL },
- { "tx", CMDL_BOOL, &off_csum_tx_wanted, NULL },
- { "sg", CMDL_BOOL, &off_sg_wanted, NULL },
- { "tso", CMDL_BOOL, &off_tso_wanted, NULL },
- { "ufo", CMDL_BOOL, &off_ufo_wanted, NULL },
- { "gso", CMDL_BOOL, &off_gso_wanted, NULL },
- { "lro", CMDL_FLAG, &off_flags_wanted, NULL,
- ETH_FLAG_LRO, &off_flags_mask },
- { "gro", CMDL_BOOL, &off_gro_wanted, NULL },
- { "rxvlan", CMDL_FLAG, &off_flags_wanted, NULL,
- ETH_FLAG_RXVLAN, &off_flags_mask },
- { "txvlan", CMDL_FLAG, &off_flags_wanted, NULL,
- ETH_FLAG_TXVLAN, &off_flags_mask },
- { "ntuple", CMDL_FLAG, &off_flags_wanted, NULL,
- ETH_FLAG_NTUPLE, &off_flags_mask },
- { "rxhash", CMDL_FLAG, &off_flags_wanted, NULL,
- ETH_FLAG_RXHASH, &off_flags_mask },
- };
+ struct cmdline_info cmdline_offload[ARRAY_SIZE(off_flag_def)];
struct ethtool_value eval;
- int err, changed = 0;
+ int err;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(off_flag_def); i++)
+ flag_to_cmdline_info(off_flag_def[i].short_name,
+ off_flag_def[i].value,
+ &off_flags_wanted, &off_flags_mask,
+ &cmdline_offload[i]);
parse_generic_cmdline(ctx, &goffload_changed,
cmdline_offload, ARRAY_SIZE(cmdline_offload));
- if (off_csum_rx_wanted >= 0) {
- changed = 1;
- eval.cmd = ETHTOOL_SRXCSUM;
- eval.data = (off_csum_rx_wanted == 1);
- err = send_ioctl(ctx, &eval);
- if (err) {
- perror("Cannot set device rx csum settings");
- return 84;
- }
- }
-
- if (off_csum_tx_wanted >= 0) {
- changed = 1;
- eval.cmd = ETHTOOL_STXCSUM;
- eval.data = (off_csum_tx_wanted == 1);
- err = send_ioctl(ctx, &eval);
- if (err) {
- perror("Cannot set device tx csum settings");
- return 85;
- }
- }
-
- if (off_sg_wanted >= 0) {
- changed = 1;
- eval.cmd = ETHTOOL_SSG;
- eval.data = (off_sg_wanted == 1);
- err = send_ioctl(ctx, &eval);
- if (err) {
- perror("Cannot set device scatter-gather settings");
- return 86;
- }
- }
-
- if (off_tso_wanted >= 0) {
- changed = 1;
- eval.cmd = ETHTOOL_STSO;
- eval.data = (off_tso_wanted == 1);
- err = send_ioctl(ctx, &eval);
- if (err) {
- perror("Cannot set device tcp segmentation offload settings");
- return 88;
- }
- }
- if (off_ufo_wanted >= 0) {
- changed = 1;
- eval.cmd = ETHTOOL_SUFO;
- eval.data = (off_ufo_wanted == 1);
- err = send_ioctl(ctx, &eval);
- if (err) {
- perror("Cannot set device udp large send offload settings");
- return 89;
- }
- }
- if (off_gso_wanted >= 0) {
- changed = 1;
- eval.cmd = ETHTOOL_SGSO;
- eval.data = (off_gso_wanted == 1);
- err = send_ioctl(ctx, &eval);
- if (err) {
- perror("Cannot set device generic segmentation offload settings");
- return 90;
+ for (i = 0; i < ARRAY_SIZE(off_flag_def); i++) {
+ if (!off_flag_def[i].set_cmd)
+ continue;
+ if (off_flags_mask & off_flag_def[i].value) {
+ eval.cmd = off_flag_def[i].set_cmd;
+ eval.data = !!(off_flags_wanted &
+ off_flag_def[i].value);
+ err = send_ioctl(ctx, &eval);
+ if (err) {
+ fprintf(stderr,
+ "Cannot set device %s settings: %m\n",
+ off_flag_def[i].long_name);
+ return 1;
+ }
}
}
- if (off_flags_mask) {
- changed = 1;
+ if (off_flags_mask & ETH_FLAG_EXT_MASK) {
eval.cmd = ETHTOOL_GFLAGS;
eval.data = 0;
err = send_ioctl(ctx, &eval);
@@ -1841,8 +1738,8 @@ static int do_soffload(struct cmd_context *ctx)
}
eval.cmd = ETHTOOL_SFLAGS;
- eval.data = ((eval.data & ~off_flags_mask) |
- off_flags_wanted);
+ eval.data &= ~(off_flags_mask & ETH_FLAG_EXT_MASK);
+ eval.data |= off_flags_wanted & ETH_FLAG_EXT_MASK;
err = send_ioctl(ctx, &eval);
if (err) {
@@ -1850,18 +1747,8 @@ static int do_soffload(struct cmd_context *ctx)
return 92;
}
}
- if (off_gro_wanted >= 0) {
- changed = 1;
- eval.cmd = ETHTOOL_SGRO;
- eval.data = (off_gro_wanted == 1);
- err = send_ioctl(ctx, &eval);
- if (err) {
- perror("Cannot set device GRO settings");
- return 93;
- }
- }
- if (!changed) {
+ if (off_flags_mask == 0) {
fprintf(stdout, "no offload settings changed\n");
}
diff --git a/internal.h b/internal.h
index 0fff2a5..deb7868 100644
--- a/internal.h
+++ b/internal.h
@@ -91,6 +91,24 @@ static inline int test_bit(unsigned int nr, const unsigned long *addr)
#define SIOCETHTOOL 0x8946
#endif
+/* Internal values for old-style offload flags. Values and names
+ * must not clash with the flags defined for ETHTOOL_{G,S}FLAGS.
+ */
+#define ETH_FLAG_RXCSUM (1 << 0)
+#define ETH_FLAG_TXCSUM (1 << 1)
+#define ETH_FLAG_SG (1 << 2)
+#define ETH_FLAG_TSO (1 << 3)
+#define ETH_FLAG_UFO (1 << 4)
+#define ETH_FLAG_GSO (1 << 5)
+#define ETH_FLAG_GRO (1 << 6)
+#define ETH_FLAG_INT_MASK (ETH_FLAG_RXCSUM | ETH_FLAG_TXCSUM | \
+ ETH_FLAG_SG | ETH_FLAG_TSO | ETH_FLAG_UFO | \
+ ETH_FLAG_GSO | ETH_FLAG_GRO),
+/* Mask of all flags defined for ETHTOOL_{G,S}FLAGS. */
+#define ETH_FLAG_EXT_MASK (ETH_FLAG_LRO | ETH_FLAG_RXVLAN | \
+ ETH_FLAG_TXVLAN | ETH_FLAG_NTUPLE | \
+ ETH_FLAG_RXHASH)
+
/* Context for sub-commands */
struct cmd_context {
const char *devname; /* net device name */
diff --git a/test-features.c b/test-features.c
index 4d8680a..349bc23 100644
--- a/test-features.c
+++ b/test-features.c
@@ -62,8 +62,8 @@ static const struct cmd_expect cmd_expect_get_features_off[] = {
{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
- { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
{ &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
+ { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
{ 0, 0, 0, 0, 0 }
};
@@ -74,9 +74,9 @@ static const struct cmd_expect cmd_expect_set_features_off[] = {
{ &cmd_stso_off, sizeof(cmd_stso_off), 0, 0, 0 },
{ &cmd_sufo_off, sizeof(cmd_sufo_off), 0, 0, 0 },
{ &cmd_sgso_off, sizeof(cmd_sgso_off), 0, 0, 0 },
+ { &cmd_sgro_off, sizeof(cmd_sgro_off), 0, 0, 0 },
{ &cmd_gflags_on, 4, 0, &cmd_gflags_on, sizeof(cmd_sflags_on) },
{ &cmd_sflags_off, sizeof(cmd_sflags_off), 0, 0, 0 },
- { &cmd_sgro_off, sizeof(cmd_sgro_off), 0, 0, 0 },
{ 0, 0, 0, 0, 0 }
};
@@ -87,9 +87,9 @@ static const struct cmd_expect cmd_expect_set_features_on[] = {
{ &cmd_stso_on, sizeof(cmd_stso_on), 0, 0, 0 },
{ &cmd_sufo_on, sizeof(cmd_sufo_on), 0, 0, 0 },
{ &cmd_sgso_on, sizeof(cmd_sgso_on), 0, 0, 0 },
+ { &cmd_sgro_on, sizeof(cmd_sgro_on), 0, 0, 0 },
{ &cmd_gflags_off, 4, 0, &cmd_gflags_on, sizeof(cmd_sflags_off) },
{ &cmd_sflags_on, sizeof(cmd_sflags_on), 0, 0, 0 },
- { &cmd_sgro_on, sizeof(cmd_sgro_on), 0, 0, 0 },
{ 0, 0, 0, 0, 0 }
};
--
1.7.7.6
--
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.
^ permalink raw reply related
* [PATCH ethtool 6/7] Report when offload feature changes are not exactly as requested
From: Ben Hutchings @ 2012-06-02 0:39 UTC (permalink / raw)
To: netdev; +Cc: Michał Mirosław, Mahesh Bandewar
In-Reply-To: <1338597227.2770.13.camel@bwh-desktop.uk.solarflarecom.com>
When an offload feature is enabled or disabled, this can change the
state of other features that depend on it, or may itself be deferred
if it depends on a feature that is disabled. Report when this
happens, and fail if no offload features could be changed.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
ethtool.c | 65 ++++++++++++++++++++++++++++++++++++++-----------------
test-features.c | 34 +++++++++++++++++++++++++++-
2 files changed, 77 insertions(+), 22 deletions(-)
diff --git a/ethtool.c b/ethtool.c
index 34d8b90..1cb708f 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -1069,13 +1069,15 @@ static int dump_coalesce(const struct ethtool_coalesce *ecoal)
return 0;
}
-static int dump_offload(u32 active)
+static int dump_offload(u32 active, u32 mask)
{
u32 value;
int i;
for (i = 0; i < ARRAY_SIZE(off_flag_def); i++) {
value = off_flag_def[i].value;
+ if (!(mask & value))
+ continue;
printf("%s: %s\n",
off_flag_def[i].long_name,
(active & value) ? "on" : "off");
@@ -1647,17 +1649,14 @@ static int do_scoalesce(struct cmd_context *ctx)
return 0;
}
-static int do_goffload(struct cmd_context *ctx)
+static int get_offload(struct cmd_context *ctx, u32 *flags)
{
struct ethtool_value eval;
int err, allfail = 1;
- u32 flags = 0, value;
+ u32 value;
int i;
- if (ctx->argc != 0)
- exit_bad_args();
-
- fprintf(stdout, "Offload parameters for %s:\n", ctx->devname);
+ *flags = 0;
for (i = 0; i < ARRAY_SIZE(off_flag_def); i++) {
value = off_flag_def[i].value;
@@ -1671,7 +1670,7 @@ static int do_goffload(struct cmd_context *ctx)
off_flag_def[i].long_name);
} else {
if (eval.data)
- flags |= value;
+ *flags |= value;
allfail = 0;
}
}
@@ -1681,16 +1680,28 @@ static int do_goffload(struct cmd_context *ctx)
if (err) {
perror("Cannot get device flags");
} else {
- flags |= eval.data & ETH_FLAG_EXT_MASK;
+ *flags |= eval.data & ETH_FLAG_EXT_MASK;
allfail = 0;
}
- if (allfail) {
+ return allfail;
+}
+
+static int do_goffload(struct cmd_context *ctx)
+{
+ u32 flags;
+
+ if (ctx->argc != 0)
+ exit_bad_args();
+
+ fprintf(stdout, "Offload parameters for %s:\n", ctx->devname);
+
+ if (get_offload(ctx, &flags)) {
fprintf(stdout, "no offload info available\n");
return 83;
}
- return dump_offload(flags);
+ return dump_offload(flags, ~(u32)0);
}
static int do_soffload(struct cmd_context *ctx)
@@ -1699,6 +1710,7 @@ static int do_soffload(struct cmd_context *ctx)
u32 off_flags_wanted = 0;
u32 off_flags_mask = 0;
struct cmdline_info cmdline_offload[ARRAY_SIZE(off_flag_def)];
+ u32 old_flags, new_flags, diff;
struct ethtool_value eval;
int err;
int i;
@@ -1712,6 +1724,11 @@ static int do_soffload(struct cmd_context *ctx)
parse_generic_cmdline(ctx, &goffload_changed,
cmdline_offload, ARRAY_SIZE(cmdline_offload));
+ if (get_offload(ctx, &old_flags)) {
+ fprintf(stderr, "no offload info available\n");
+ return 1;
+ }
+
for (i = 0; i < ARRAY_SIZE(off_flag_def); i++) {
if (!off_flag_def[i].set_cmd)
continue;
@@ -1729,16 +1746,8 @@ static int do_soffload(struct cmd_context *ctx)
}
}
if (off_flags_mask & ETH_FLAG_EXT_MASK) {
- eval.cmd = ETHTOOL_GFLAGS;
- eval.data = 0;
- err = send_ioctl(ctx, &eval);
- if (err) {
- perror("Cannot get device flag settings");
- return 91;
- }
-
eval.cmd = ETHTOOL_SFLAGS;
- eval.data &= ~(off_flags_mask & ETH_FLAG_EXT_MASK);
+ eval.data = old_flags & ~off_flags_mask & ETH_FLAG_EXT_MASK;
eval.data |= off_flags_wanted & ETH_FLAG_EXT_MASK;
err = send_ioctl(ctx, &eval);
@@ -1750,6 +1759,22 @@ static int do_soffload(struct cmd_context *ctx)
if (off_flags_mask == 0) {
fprintf(stdout, "no offload settings changed\n");
+ return 0;
+ }
+
+ /* Compare new state with requested state */
+ if (get_offload(ctx, &new_flags)) {
+ fprintf(stderr, "no offload info available\n");
+ return 1;
+ }
+ if (new_flags != ((old_flags & ~off_flags_mask) | off_flags_wanted)) {
+ if (new_flags == old_flags) {
+ fprintf(stderr,
+ "Could not change any device offload settings\n");
+ return 1;
+ }
+ printf("Actual changes:\n");
+ dump_offload(new_flags, new_flags ^ old_flags);
}
return 0;
diff --git a/test-features.c b/test-features.c
index 349bc23..409b3d2 100644
--- a/test-features.c
+++ b/test-features.c
@@ -68,6 +68,14 @@ static const struct cmd_expect cmd_expect_get_features_off[] = {
};
static const struct cmd_expect cmd_expect_set_features_off[] = {
+ { &cmd_grxcsum_on, 4, 0, &cmd_grxcsum_on, sizeof(cmd_grxcsum_on) },
+ { &cmd_gtxcsum_on, 4, 0, &cmd_gtxcsum_on, sizeof(cmd_gtxcsum_on) },
+ { &cmd_gsg_on, 4, 0, &cmd_gsg_on, sizeof(cmd_gsg_on) },
+ { &cmd_gtso_on, 4, 0, &cmd_gtso_on, sizeof(cmd_gtso_on) },
+ { &cmd_gufo_on, 4, 0, &cmd_gufo_on, sizeof(cmd_gufo_on) },
+ { &cmd_ggso_on, 4, 0, &cmd_ggso_on, sizeof(cmd_ggso_on) },
+ { &cmd_ggro_on, 4,0, &cmd_ggro_on, sizeof(cmd_ggro_on) },
+ { &cmd_gflags_on, 4, 0, &cmd_gflags_on, sizeof(cmd_sflags_on) },
{ &cmd_srxcsum_off, sizeof(cmd_srxcsum_off), 0, 0, 0 },
{ &cmd_stxcsum_off, sizeof(cmd_stxcsum_off), 0, 0, 0 },
{ &cmd_ssg_off, sizeof(cmd_ssg_off), 0, 0, 0 },
@@ -75,12 +83,27 @@ static const struct cmd_expect cmd_expect_set_features_off[] = {
{ &cmd_sufo_off, sizeof(cmd_sufo_off), 0, 0, 0 },
{ &cmd_sgso_off, sizeof(cmd_sgso_off), 0, 0, 0 },
{ &cmd_sgro_off, sizeof(cmd_sgro_off), 0, 0, 0 },
- { &cmd_gflags_on, 4, 0, &cmd_gflags_on, sizeof(cmd_sflags_on) },
{ &cmd_sflags_off, sizeof(cmd_sflags_off), 0, 0, 0 },
+ { &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
+ { &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
+ { &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
+ { &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
+ { &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
+ { &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
+ { &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
+ { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_sflags_off) },
{ 0, 0, 0, 0, 0 }
};
static const struct cmd_expect cmd_expect_set_features_on[] = {
+ { &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
+ { &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
+ { &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
+ { &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
+ { &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
+ { &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
+ { &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
+ { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
{ &cmd_srxcsum_on, sizeof(cmd_srxcsum_on), 0, 0, 0 },
{ &cmd_stxcsum_on, sizeof(cmd_stxcsum_on), 0, 0, 0 },
{ &cmd_ssg_on, sizeof(cmd_ssg_on), 0, 0, 0 },
@@ -88,8 +111,15 @@ static const struct cmd_expect cmd_expect_set_features_on[] = {
{ &cmd_sufo_on, sizeof(cmd_sufo_on), 0, 0, 0 },
{ &cmd_sgso_on, sizeof(cmd_sgso_on), 0, 0, 0 },
{ &cmd_sgro_on, sizeof(cmd_sgro_on), 0, 0, 0 },
- { &cmd_gflags_off, 4, 0, &cmd_gflags_on, sizeof(cmd_sflags_off) },
{ &cmd_sflags_on, sizeof(cmd_sflags_on), 0, 0, 0 },
+ { &cmd_grxcsum_on, 4, 0, &cmd_grxcsum_on, sizeof(cmd_grxcsum_on) },
+ { &cmd_gtxcsum_on, 4, 0, &cmd_gtxcsum_on, sizeof(cmd_gtxcsum_on) },
+ { &cmd_gsg_on, 4, 0, &cmd_gsg_on, sizeof(cmd_gsg_on) },
+ { &cmd_gtso_on, 4, 0, &cmd_gtso_on, sizeof(cmd_gtso_on) },
+ { &cmd_gufo_on, 4, 0, &cmd_gufo_on, sizeof(cmd_gufo_on) },
+ { &cmd_ggso_on, 4, 0, &cmd_ggso_on, sizeof(cmd_ggso_on) },
+ { &cmd_ggro_on, 4,0, &cmd_ggro_on, sizeof(cmd_ggro_on) },
+ { &cmd_gflags_on, 4, 0, &cmd_gflags_on, sizeof(cmd_sflags_on) },
{ 0, 0, 0, 0, 0 }
};
--
1.7.7.6
--
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.
^ permalink raw reply related
* [PATCH ethtool 7/7] Change -k/-K options to use ETHTOOL_{G,S}FEATURES
From: Ben Hutchings @ 2012-06-02 0:40 UTC (permalink / raw)
To: netdev; +Cc: Michał Mirosław, Mahesh Bandewar
In-Reply-To: <1338597227.2770.13.camel@bwh-desktop.uk.solarflarecom.com>
Rewrite the offload get and set functions to use the generic features
API where available, while maintaining a similar output format.
Add the long options --show-features and --features as additional
aliases for -k and -K.
Where there is exactly one named feature corresponding to an old
offload name, show the feature using the old offload name. Where
there are multiple features corresponding to an old offload name,
show the features as a group, indented underneath it.
Add some test cases to check that this works properly with or without
the generic features API. (These may well be insufficient.)
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
ethtool.8.in | 31 ++---
ethtool.c | 448 +++++++++++++++++++++++++++++++++++++++++++-----------
test-cmdline.c | 7 -
test-features.c | 345 +++++++++++++++++++++++++++++++++++++++++-
4 files changed, 707 insertions(+), 124 deletions(-)
diff --git a/ethtool.8.in b/ethtool.8.in
index 523b737..70ae31d 100644
--- a/ethtool.8.in
+++ b/ethtool.8.in
@@ -199,23 +199,13 @@ ethtool \- query or control network driver and hardware settings
.BN length
.BN value
.HP
-.B ethtool \-k|\-\-show\-offload
+.B ethtool \-k|\-\-show\-features|\-\-show\-offload
.I devname
.HP
-.B ethtool \-K|\-\-offload
-.I devname
-.B2 rx on off
-.B2 tx on off
-.B2 sg on off
-.B2 tso on off
-.B2 ufo on off
-.B2 gso on off
-.B2 gro on off
-.B2 lro on off
-.B2 rxvlan on off
-.B2 txvlan on off
-.B2 ntuple on off
-.B2 rxhash on off
+.B ethtool \-K|\-\-features|\-\-offload
+.I devname feature
+.A1 on off
+.RB ...
.HP
.B ethtool \-p|\-\-identify
.I devname
@@ -428,11 +418,14 @@ parameters allow writing to certain portions of the EEPROM.
Because of the persistent nature of writing to the EEPROM, a device-specific
magic key must be specified to prevent the accidental writing to the EEPROM.
.TP
-.B \-k \-\-show\-offload
-Queries the specified network device for offload information.
+.B \-k \-\-show\-features \-\-show\-offload
+Queries the specified network device for the state of protocol
+offload and other features.
.TP
-.B \-K \-\-offload
-Changes the offload parameters of the specified network device.
+.B \-K \-\-features \-\-offload
+Changes the offload parameters and other features of the specified
+network device. The following feature names are built-in and others
+may be defined by the kernel.
.TP
.A2 rx on off
Specifies whether RX checksumming should be enabled.
diff --git a/ethtool.c b/ethtool.c
index 1cb708f..984273b 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -128,38 +128,63 @@ static const struct flag_info flags_msglvl[] = {
{ "wol", NETIF_MSG_WOL },
};
-static const struct {
+struct off_flag_def {
const char *short_name;
const char *long_name;
+ const char *kernel_name;
u32 get_cmd, set_cmd;
u32 value;
-} off_flag_def[] = {
- { "rx", "rx-checksumming",
+};
+static const struct off_flag_def off_flag_def[] = {
+ { "rx", "rx-checksumming", "rx-checksum",
ETHTOOL_GRXCSUM, ETHTOOL_SRXCSUM, ETH_FLAG_RXCSUM },
- { "tx", "tx-checksumming",
+ { "tx", "tx-checksumming", "tx-checksum-*",
ETHTOOL_GTXCSUM, ETHTOOL_STXCSUM, ETH_FLAG_TXCSUM },
- { "sg", "scatter-gather",
+ { "sg", "scatter-gather", "tx-scatter-gather*",
ETHTOOL_GSG, ETHTOOL_SSG, ETH_FLAG_SG },
- { "tso", "tcp-segmentation-offload",
+ { "tso", "tcp-segmentation-offload", "tx-tcp*-segmentation",
ETHTOOL_GTSO, ETHTOOL_STSO, ETH_FLAG_TSO },
- { "ufo", "udp-fragmentation-offload",
+ { "ufo", "udp-fragmentation-offload", "tx-udp-fragmentation",
ETHTOOL_GUFO, ETHTOOL_SUFO, ETH_FLAG_UFO },
- { "gso", "generic-segmentation-offload",
+ { "gso", "generic-segmentation-offload", "tx-generic-segmentation",
ETHTOOL_GGSO, ETHTOOL_SGSO, ETH_FLAG_GSO },
- { "gro", "generic-receive-offload",
+ { "gro", "generic-receive-offload", "rx-gro",
ETHTOOL_GGRO, ETHTOOL_SGRO, ETH_FLAG_GRO },
- { "lro", "large-receive-offload",
+ { "lro", "large-receive-offload", "rx-lro",
0, 0, ETH_FLAG_LRO },
- { "rxvlan", "rx-vlan-offload",
+ { "rxvlan", "rx-vlan-offload", "rx-vlan-hw-parse",
0, 0, ETH_FLAG_RXVLAN },
- { "txvlan", "tx-vlan-offload",
+ { "txvlan", "tx-vlan-offload", "tx-vlan-hw-insert",
0, 0, ETH_FLAG_TXVLAN },
- { "ntuple", "ntuple-filters",
+ { "ntuple", "ntuple-filters", "rx-ntuple-filter",
0, 0, ETH_FLAG_NTUPLE },
- { "rxhash", "receive-hashing",
+ { "rxhash", "receive-hashing", "rx-hashing",
0, 0, ETH_FLAG_RXHASH },
};
+struct feature_def {
+ char name[ETH_GSTRING_LEN];
+ int off_flag_index; /* index in off_flag_def; negative if none match */
+};
+
+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)];
+ /* Name and offload flag index for each feature */
+ struct feature_def def[0];
+};
+
+#define FEATURE_BITS_TO_BLOCKS(n_bits) DIV_ROUND_UP(n_bits, 32U)
+#define FEATURE_WORD(blocks, index, field) ((blocks)[(index) / 32U].field)
+#define FEATURE_FIELD_FLAG(index) (1U << (index) % 32U)
+#define FEATURE_BIT_SET(blocks, index, field) \
+ (FEATURE_WORD(blocks, index, field) |= FEATURE_FIELD_FLAG(index))
+#define FEATURE_BIT_CLEAR(blocks, index, field) \
+ (FEATURE_WORD(blocks, index, filed) &= ~FEATURE_FIELD_FLAG(index))
+#define FEATURE_BIT_IS_SET(blocks, index, field) \
+ (FEATURE_WORD(blocks, index, field) & FEATURE_FIELD_FLAG(index))
+
static long long
get_int_range(char *str, int base, long long min, long long max)
{
@@ -1069,21 +1094,84 @@ static int dump_coalesce(const struct ethtool_coalesce *ecoal)
return 0;
}
-static int dump_offload(u32 active, u32 mask)
+struct feature_state {
+ u32 off_flags;
+ struct ethtool_gfeatures features;
+};
+
+static void dump_one_feature(const char *indent, const char *name,
+ const struct feature_state *state,
+ const struct feature_state *ref_state,
+ u32 index)
+{
+ if (ref_state &&
+ !(FEATURE_BIT_IS_SET(state->features.features, index, active) ^
+ FEATURE_BIT_IS_SET(ref_state->features.features, index, active)))
+ return;
+
+ printf("%s%s: %s%s\n",
+ indent, name,
+ FEATURE_BIT_IS_SET(state->features.features, index, active) ?
+ "on" : "off",
+ (!FEATURE_BIT_IS_SET(state->features.features, index, available)
+ || FEATURE_BIT_IS_SET(state->features.features, index,
+ never_changed))
+ ? " [fixed]"
+ : (FEATURE_BIT_IS_SET(state->features.features, index, requested)
+ ^ FEATURE_BIT_IS_SET(state->features.features, index, active))
+ ? (FEATURE_BIT_IS_SET(state->features.features, index, requested)
+ ? " [requested on]" : " [requested off]")
+ : "");
+}
+
+static void dump_features(const struct feature_defs *defs,
+ const struct feature_state *state,
+ const struct feature_state *ref_state)
{
u32 value;
- int i;
+ int indent;
+ int i, j;
for (i = 0; i < ARRAY_SIZE(off_flag_def); i++) {
value = off_flag_def[i].value;
- if (!(mask & value))
- continue;
- printf("%s: %s\n",
- off_flag_def[i].long_name,
- (active & value) ? "on" : "off");
+
+ /* If this offload flag matches exactly one generic
+ * feature then it's redundant to show the flag and
+ * feature states separately. Otherwise, show the
+ * flag state first.
+ */
+ if (defs->off_flag_matched[i] != 1 &&
+ (!ref_state ||
+ (state->off_flags ^ ref_state->off_flags) & value)) {
+ printf("%s: %s\n",
+ off_flag_def[i].long_name,
+ (state->off_flags & value) ? "on" : "off");
+ indent = 1;
+ } else {
+ indent = 0;
+ }
+
+ /* Show matching features */
+ for (j = 0; j < defs->n_features; j++) {
+ if (defs->def[j].off_flag_index != i)
+ continue;
+ if (defs->off_flag_matched[i] != 1)
+ /* Show all matching feature states */
+ dump_one_feature(indent ? "\t" : "",
+ defs->def[j].name,
+ state, ref_state, j);
+ else
+ /* Show full state with the old flag name */
+ dump_one_feature("", off_flag_def[i].long_name,
+ state, ref_state, j);
+ }
}
- return 0;
+ /* Show all unmatched features that have non-null names */
+ for (j = 0; j < defs->n_features; j++)
+ if (defs->def[j].off_flag_index < 0 && defs->def[j].name[0])
+ dump_one_feature("", defs->def[j].name,
+ state, ref_state, j);
}
static int dump_rxfhash(int fhash, u64 val)
@@ -1259,6 +1347,72 @@ get_stringset(struct cmd_context *ctx, enum ethtool_stringset set_id,
return strings;
}
+static struct feature_defs *get_feature_defs(struct cmd_context *ctx)
+{
+ struct ethtool_gstrings *names;
+ struct feature_defs *defs;
+ u32 n_features;
+ int i, j;
+
+ names = get_stringset(ctx, ETH_SS_FEATURES, 0);
+ if (names) {
+ n_features = names->len;
+ } else if (errno == EOPNOTSUPP || errno == EINVAL) {
+ /* Kernel doesn't support named features; not an error */
+ n_features = 0;
+ } else {
+ return NULL;
+ }
+
+ defs = malloc(sizeof(*defs) + sizeof(defs->def[0]) * n_features);
+ if (!defs)
+ return NULL;
+
+ defs->n_features = n_features;
+ memset(defs->off_flag_matched, 0, sizeof(defs->off_flag_matched));
+
+ /* Copy out feature names and find those associated with legacy flags */
+ for (i = 0; i < defs->n_features; i++) {
+ memcpy(defs->def[i].name, names->data + i * ETH_GSTRING_LEN,
+ ETH_GSTRING_LEN);
+ defs->def[i].off_flag_index = -1;
+
+ for (j = 0;
+ j < ARRAY_SIZE(off_flag_def) &&
+ defs->def[i].off_flag_index < 0;
+ j++) {
+ const char *pattern =
+ off_flag_def[j].kernel_name;
+ const char *name = defs->def[i].name;
+ for (;;) {
+ if (*pattern == '*') {
+ /* There is only one wildcard; so
+ * switch to a suffix comparison */
+ size_t pattern_len =
+ strlen(pattern + 1);
+ size_t name_len = strlen(name);
+ if (name_len < pattern_len)
+ break; /* name is too short */
+ name += name_len - pattern_len;
+ ++pattern;
+ } else if (*pattern != *name) {
+ break; /* mismatch */
+ } else if (*pattern == 0) {
+ defs->def[i].off_flag_index = j;
+ defs->off_flag_matched[j]++;
+ break;
+ } else {
+ ++name;
+ ++pattern;
+ }
+ }
+ }
+ }
+
+ free(names);
+ return defs;
+}
+
static int do_gdrv(struct cmd_context *ctx)
{
int err;
@@ -1649,14 +1803,22 @@ static int do_scoalesce(struct cmd_context *ctx)
return 0;
}
-static int get_offload(struct cmd_context *ctx, u32 *flags)
+static struct feature_state *
+get_features(struct cmd_context *ctx, const struct feature_defs *defs)
{
+ struct feature_state *state;
struct ethtool_value eval;
int err, allfail = 1;
u32 value;
int i;
- *flags = 0;
+ state = malloc(sizeof(*state) +
+ FEATURE_BITS_TO_BLOCKS(defs->n_features) *
+ sizeof(state->features.features[0]));
+ if (!state)
+ return NULL;
+
+ state->off_flags = 0;
for (i = 0; i < ARRAY_SIZE(off_flag_def); i++) {
value = off_flag_def[i].value;
@@ -1670,7 +1832,7 @@ static int get_offload(struct cmd_context *ctx, u32 *flags)
off_flag_def[i].long_name);
} else {
if (eval.data)
- *flags |= value;
+ state->off_flags |= value;
allfail = 0;
}
}
@@ -1680,101 +1842,214 @@ static int get_offload(struct cmd_context *ctx, u32 *flags)
if (err) {
perror("Cannot get device flags");
} else {
- *flags |= eval.data & ETH_FLAG_EXT_MASK;
+ state->off_flags |= eval.data & ETH_FLAG_EXT_MASK;
allfail = 0;
}
- return allfail;
+ if (defs->n_features) {
+ state->features.cmd = ETHTOOL_GFEATURES;
+ state->features.size = FEATURE_BITS_TO_BLOCKS(defs->n_features);
+ err = send_ioctl(ctx, &state->features);
+ if (err)
+ perror("Cannot get device generic features");
+ else
+ allfail = 0;
+ }
+
+ if (allfail) {
+ free(state);
+ return NULL;
+ }
+
+ return state;
}
-static int do_goffload(struct cmd_context *ctx)
+static int do_gfeatures(struct cmd_context *ctx)
{
- u32 flags;
+ struct feature_defs *defs;
+ struct feature_state *features;
if (ctx->argc != 0)
exit_bad_args();
- fprintf(stdout, "Offload parameters for %s:\n", ctx->devname);
+ defs = get_feature_defs(ctx);
+ if (!defs)
+ return 1;
+
+ fprintf(stdout, "Features for %s:\n", ctx->devname);
- if (get_offload(ctx, &flags)) {
- fprintf(stdout, "no offload info available\n");
- return 83;
+ features = get_features(ctx, defs);
+ if (!features) {
+ fprintf(stdout, "no feature info available\n");
+ return 1;
}
- return dump_offload(flags, ~(u32)0);
+ dump_features(defs, features, NULL);
+ return 0;
}
-static int do_soffload(struct cmd_context *ctx)
+static int do_sfeatures(struct cmd_context *ctx)
{
- int goffload_changed = 0;
+ struct feature_defs *defs;
+ int any_changed = 0, any_mismatch = 0;
u32 off_flags_wanted = 0;
u32 off_flags_mask = 0;
- struct cmdline_info cmdline_offload[ARRAY_SIZE(off_flag_def)];
- u32 old_flags, new_flags, diff;
+ struct ethtool_sfeatures *efeatures;
+ struct cmdline_info *cmdline_features;
+ struct feature_state *old_state, *new_state;
struct ethtool_value eval;
int err;
- int i;
+ int i, j;
+
+ defs = get_feature_defs(ctx);
+ if (!defs)
+ return 1;
+ if (defs->n_features) {
+ efeatures = malloc(sizeof(*efeatures) +
+ FEATURE_BITS_TO_BLOCKS(defs->n_features) *
+ sizeof(efeatures->features[0]));
+ if (!efeatures) {
+ perror("Cannot parse arguments");
+ return 1;
+ }
+ efeatures->cmd = ETHTOOL_SFEATURES;
+ efeatures->size = FEATURE_BITS_TO_BLOCKS(defs->n_features);
+ 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,
+ sizeof(cmdline_features[0]));
+ if (!cmdline_features) {
+ perror("Cannot parse arguments");
+ return 1;
+ }
for (i = 0; i < ARRAY_SIZE(off_flag_def); i++)
flag_to_cmdline_info(off_flag_def[i].short_name,
off_flag_def[i].value,
&off_flags_wanted, &off_flags_mask,
- &cmdline_offload[i]);
-
- parse_generic_cmdline(ctx, &goffload_changed,
- cmdline_offload, ARRAY_SIZE(cmdline_offload));
+ &cmdline_features[i]);
+ 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]);
+ parse_generic_cmdline(ctx, &any_changed, cmdline_features,
+ ARRAY_SIZE(off_flag_def) + defs->n_features);
+ free(cmdline_features);
+
+ if (!any_changed) {
+ fprintf(stdout, "no features changed\n");
+ return 0;
+ }
- if (get_offload(ctx, &old_flags)) {
- fprintf(stderr, "no offload info available\n");
+ old_state = get_features(ctx, defs);
+ if (!old_state)
return 1;
- }
+ /* For each offload that the user specified, update any
+ * 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++) {
- if (!off_flag_def[i].set_cmd)
+ int fixed = 1;
+
+ if (!(off_flags_mask & off_flag_def[i].value))
continue;
- if (off_flags_mask & off_flag_def[i].value) {
- eval.cmd = off_flag_def[i].set_cmd;
- eval.data = !!(off_flags_wanted &
- off_flag_def[i].value);
- err = send_ioctl(ctx, &eval);
- if (err) {
- fprintf(stderr,
- "Cannot set device %s settings: %m\n",
- off_flag_def[i].long_name);
- return 1;
+
+ for (j = 0; j < defs->n_features; j++) {
+ if (defs->def[j].off_flag_index != i ||
+ !FEATURE_BIT_IS_SET(old_state->features.features,
+ j, available) ||
+ FEATURE_BIT_IS_SET(old_state->features.features,
+ j, never_changed))
+ continue;
+
+ fixed = 0;
+ if (!FEATURE_BIT_IS_SET(efeatures->features, j, valid)) {
+ FEATURE_BIT_SET(efeatures->features, j, valid);
+ if (off_flags_wanted & off_flag_def[i].value)
+ FEATURE_BIT_SET(efeatures->features, j,
+ requested);
}
}
+
+ if (fixed)
+ fprintf(stderr, "Cannot change %s\n",
+ off_flag_def[i].long_name);
}
- if (off_flags_mask & ETH_FLAG_EXT_MASK) {
- eval.cmd = ETHTOOL_SFLAGS;
- eval.data = old_flags & ~off_flags_mask & ETH_FLAG_EXT_MASK;
- eval.data |= off_flags_wanted & ETH_FLAG_EXT_MASK;
- err = send_ioctl(ctx, &eval);
- if (err) {
- perror("Cannot set device flag settings");
- return 92;
+ if (efeatures) {
+ err = send_ioctl(ctx, efeatures);
+ if (err < 0) {
+ perror("Cannot set device feature settings");
+ return 1;
+ }
+ } else {
+ for (i = 0; i < ARRAY_SIZE(off_flag_def); i++) {
+ if (!off_flag_def[i].set_cmd)
+ continue;
+ if (off_flags_mask & off_flag_def[i].value) {
+ eval.cmd = off_flag_def[i].set_cmd;
+ eval.data = !!(off_flags_wanted &
+ off_flag_def[i].value);
+ err = send_ioctl(ctx, &eval);
+ if (err) {
+ fprintf(stderr,
+ "Cannot set device %s settings: %m\n",
+ off_flag_def[i].long_name);
+ return 1;
+ }
+ }
}
- }
- if (off_flags_mask == 0) {
- fprintf(stdout, "no offload settings changed\n");
- return 0;
+ if (off_flags_mask & ETH_FLAG_EXT_MASK) {
+ eval.cmd = ETHTOOL_SFLAGS;
+ eval.data = (old_state->off_flags & ~off_flags_mask &
+ ETH_FLAG_EXT_MASK);
+ eval.data |= off_flags_wanted & ETH_FLAG_EXT_MASK;
+
+ err = send_ioctl(ctx, &eval);
+ if (err) {
+ perror("Cannot set device flag settings");
+ return 92;
+ }
+ }
}
/* Compare new state with requested state */
- if (get_offload(ctx, &new_flags)) {
- fprintf(stderr, "no offload info available\n");
+ new_state = get_features(ctx, defs);
+ if (!new_state)
return 1;
- }
- if (new_flags != ((old_flags & ~off_flags_mask) | off_flags_wanted)) {
- if (new_flags == old_flags) {
+ any_changed = new_state->off_flags != old_state->off_flags;
+ any_mismatch = (new_state->off_flags !=
+ ((old_state->off_flags & ~off_flags_mask) |
+ off_flags_wanted));
+ for (i = 0; i < FEATURE_BITS_TO_BLOCKS(defs->n_features); i++) {
+ if (new_state->features.features[i].active !=
+ old_state->features.features[i].active)
+ any_changed = 1;
+ if (new_state->features.features[i].active !=
+ ((old_state->features.features[i].active &
+ ~efeatures->features[i].valid) |
+ efeatures->features[i].requested))
+ any_mismatch = 1;
+ }
+ if (any_mismatch) {
+ if (!any_changed) {
fprintf(stderr,
- "Could not change any device offload settings\n");
+ "Could not change any device features\n");
return 1;
}
printf("Actual changes:\n");
- dump_offload(new_flags, new_flags ^ old_flags);
+ dump_features(defs, new_state, old_state);
}
return 0;
@@ -3237,22 +3512,11 @@ static const struct option {
" [ rx-mini N ]\n"
" [ rx-jumbo N ]\n"
" [ tx N ]\n" },
- { "-k|--show-offload", 1, do_goffload,
- "Get protocol offload information" },
- { "-K|--offload", 1, do_soffload, "Set protocol offload",
- " [ rx on|off ]\n"
- " [ tx on|off ]\n"
- " [ sg on|off ]\n"
- " [ tso on|off ]\n"
- " [ ufo on|off ]\n"
- " [ gso on|off ]\n"
- " [ gro on|off ]\n"
- " [ lro on|off ]\n"
- " [ rxvlan on|off ]\n"
- " [ txvlan on|off ]\n"
- " [ ntuple on|off ]\n"
- " [ rxhash on|off ]\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"
diff --git a/test-cmdline.c b/test-cmdline.c
index c62bb97..978c312 100644
--- a/test-cmdline.c
+++ b/test-cmdline.c
@@ -86,14 +86,7 @@ static struct test_case {
{ 1, "--set-ring devname rx" },
{ 1, "-G devname foo 1" },
{ 1, "-G" },
- { 0, "-k devname" },
- { 0, "--show-offload devname" },
{ 1, "-k" },
- { 0, "-K devname rx on tx off sg on tso off ufo on gso off gro on" },
- { 0, "--offload devname lro off rxvlan on txvlan off ntuple on rxhash off" },
- { 1, "-K devname rx foo" },
- { 1, "--offload devname rx" },
- { 1, "-K devname foo on" },
{ 1, "-K" },
{ 0, "-i devname" },
{ 0, "--driver devname" },
diff --git a/test-features.c b/test-features.c
index 409b3d2..a48c701 100644
--- a/test-features.c
+++ b/test-features.c
@@ -7,12 +7,19 @@
* by the Free Software Foundation, incorporated herein by reference.
*/
+#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TEST_NO_WRAPPERS
#include "internal.h"
+static const struct {
+ struct ethtool_sset_info cmd;
+ u32 data[1];
+}
+cmd_gssetinfo = { { ETHTOOL_GSSET_INFO, 0, 1ULL << ETH_SS_FEATURES }, 34 };
+
static const struct ethtool_value
cmd_grxcsum_off = { ETHTOOL_GRXCSUM, 0 },
cmd_grxcsum_on = { ETHTOOL_GRXCSUM, 1 },
@@ -55,7 +62,13 @@ cmd_sflags_not_rxhash = { ETHTOOL_SFLAGS,
ETH_FLAG_LRO | ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN |
ETH_FLAG_NTUPLE };
-static const struct cmd_expect cmd_expect_get_features_off[] = {
+static const struct cmd_expect cmd_expect_get_strings_old[] = {
+ { &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd), -EINVAL },
+ { 0, 0, 0, 0, 0 }
+};
+
+static const struct cmd_expect cmd_expect_get_features_off_old[] = {
+ { &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd), -EINVAL },
{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
@@ -67,7 +80,8 @@ static const struct cmd_expect cmd_expect_get_features_off[] = {
{ 0, 0, 0, 0, 0 }
};
-static const struct cmd_expect cmd_expect_set_features_off[] = {
+static const struct cmd_expect cmd_expect_set_features_off_old[] = {
+ { &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd), -EINVAL },
{ &cmd_grxcsum_on, 4, 0, &cmd_grxcsum_on, sizeof(cmd_grxcsum_on) },
{ &cmd_gtxcsum_on, 4, 0, &cmd_gtxcsum_on, sizeof(cmd_gtxcsum_on) },
{ &cmd_gsg_on, 4, 0, &cmd_gsg_on, sizeof(cmd_gsg_on) },
@@ -95,7 +109,8 @@ static const struct cmd_expect cmd_expect_set_features_off[] = {
{ 0, 0, 0, 0, 0 }
};
-static const struct cmd_expect cmd_expect_set_features_on[] = {
+static const struct cmd_expect cmd_expect_set_features_on_old[] = {
+ { &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd), -EINVAL },
{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
@@ -123,16 +138,334 @@ static const struct cmd_expect cmd_expect_set_features_on[] = {
{ 0, 0, 0, 0, 0 }
};
+static const struct cmd_expect cmd_expect_set_features_unsup_on_old[] = {
+ { &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd), -EINVAL },
+ { &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
+ { &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
+ { &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
+ { &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
+ { &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
+ { &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
+ { &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
+ { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
+ { &cmd_stxcsum_on, sizeof(cmd_stxcsum_on), -EOPNOTSUPP },
+ { 0, 0, 0, 0, 0 }
+};
+
+static const struct {
+ struct ethtool_gstrings cmd;
+ u8 data[34][ETH_GSTRING_LEN];
+}
+cmd_gstrings = {
+ { ETHTOOL_GSTRINGS, ETH_SS_FEATURES, 34 },
+ {
+ "tx-scatter-gather",
+ "tx-checksum-ipv4",
+ "",
+ "tx-checksum-ip-generic",
+ "tx-checksum-ipv6",
+ "highdma",
+ "tx-scatter-gather-fraglist",
+ "tx-vlan-hw-insert",
+ "rx-vlan-hw-parse",
+ "rx-vlan-filter",
+ "vlan-challenged",
+ "tx-generic-segmentation",
+ "tx-lockless",
+ "netns-local",
+ "rx-gro",
+ "rx-lro",
+ "tx-tcp-segmentation",
+ "tx-udp-fragmentation",
+ "tx-gso-robust",
+ "tx-tcp-ecn-segmentation",
+ "tx-tcp6-segmentation",
+ "tx-fcoe-segmentation",
+ "",
+ "",
+ "tx-checksum-fcoe-crc",
+ "tx-checksum-sctp",
+ "fcoe-mtu",
+ "rx-ntuple-filter",
+ "rx-hashing",
+ "rx-checksum",
+ "tx-nocache-copy",
+ "loopback",
+ "rx-fcs",
+ "rx-all",
+ }
+};
+
+static const struct {
+ struct ethtool_gfeatures cmd;
+ struct ethtool_get_features_block data[2];
+}
+ /* available requested active never_changed */
+/* minimal: only GRO and GSO are available (and GSO won't work) */
+cmd_gfeatures_min_off = { { ETHTOOL_GFEATURES, 2 },
+ {{ 0x00004800, 0x00000000, 0x00000000, 0x00003400},
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000}}
+},
+cmd_gfeatures_min_on = { { ETHTOOL_GFEATURES, 2 },
+ {{ 0x00004800, 0x00004800, 0x00004000, 0x00003400},
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000}}
+},
+/* maximal: everything that isn't never-changed is available */
+cmd_gfeatures_max_off = { { ETHTOOL_GFEATURES, 2 },
+ {{ 0xffffcbff, 0x00000000, 0x00000000, 0x00003400 },
+ { 0x00000003, 0x00000000, 0x00000000, 0x00000000 }}
+},
+cmd_gfeatures_max_on = { { ETHTOOL_GFEATURES, 2 },
+ {{ 0xffffcbff, 0xffffcbff, 0xffffcbff, 0x00003400 },
+ { 0x00000003, 0x00000003, 0x00000003, 0x00000000 }}
+},
+/* IPv4: GRO, GSO, SG and some IPv4-specific offloads are available */
+cmd_gfeatures_ipv4_off = { { ETHTOOL_GFEATURES, 2 },
+ {{ 0x00014803, 0x00000000, 0x00000000, 0x00003400 },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }}
+},
+cmd_gfeatures_ipv4_on = { { ETHTOOL_GFEATURES, 2 },
+ {{ 0x00014803, 0x00014803, 0x00014803, 0x00003400 },
+ { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }}
+};
+
+static const struct {
+ struct ethtool_sfeatures cmd;
+ struct ethtool_set_features_block data[2];
+}
+ /* valid requested */
+cmd_sfeatures_min_on = { { ETHTOOL_SFEATURES, 2 },
+ {{ 0x00004800, 0x00004800 },
+ { 0x00000000, 0x00000000 }} },
+cmd_sfeatures_min_off = { { ETHTOOL_SFEATURES, 2 },
+ {{ 0x00004800, 0x00000000 },
+ { 0x00000000, 0x00000000 }} },
+cmd_sfeatures_noop = { { ETHTOOL_SFEATURES, 2 },
+ {{ 0x00000000, 0x00000000 },
+ { 0x00000000, 0x00000000 }} },
+cmd_sfeatures_ipv4_on = { { ETHTOOL_SFEATURES, 2 },
+ {{ 0x00014803, 0x00014803 },
+ { 0x00000000, 0x00000000 }} };
+
+static const struct cmd_expect cmd_expect_get_strings[] = {
+ { &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd),
+ 0, &cmd_gssetinfo, sizeof(cmd_gssetinfo) },
+ { &cmd_gstrings, sizeof(cmd_gstrings.cmd),
+ 0, &cmd_gstrings, sizeof(cmd_gstrings) },
+ { 0, 0, 0, 0, 0 }
+};
+
+static const struct cmd_expect cmd_expect_get_features_min_off[] = {
+ { &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd),
+ 0, &cmd_gssetinfo, sizeof(cmd_gssetinfo) },
+ { &cmd_gstrings, sizeof(cmd_gstrings.cmd),
+ 0, &cmd_gstrings, sizeof(cmd_gstrings) },
+ { &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
+ { &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
+ { &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
+ { &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
+ { &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
+ { &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
+ { &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
+ { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
+ { &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off.cmd),
+ 0, &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off) },
+ { 0, 0, 0, 0, 0 }
+};
+
+static const struct cmd_expect cmd_expect_get_features_max_on[] = {
+ { &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd),
+ 0, &cmd_gssetinfo, sizeof(cmd_gssetinfo) },
+ { &cmd_gstrings, sizeof(cmd_gstrings.cmd),
+ 0, &cmd_gstrings, sizeof(cmd_gstrings) },
+ { &cmd_grxcsum_on, 4, 0, &cmd_grxcsum_on, sizeof(cmd_grxcsum_on) },
+ { &cmd_gtxcsum_on, 4, 0, &cmd_gtxcsum_on, sizeof(cmd_gtxcsum_on) },
+ { &cmd_gsg_on, 4, 0, &cmd_gsg_on, sizeof(cmd_gsg_on) },
+ { &cmd_gtso_on, 4, 0, &cmd_gtso_on, sizeof(cmd_gtso_on) },
+ { &cmd_gufo_on, 4, 0, &cmd_gufo_on, sizeof(cmd_gufo_on) },
+ { &cmd_ggso_on, 4, 0, &cmd_ggso_on, sizeof(cmd_ggso_on) },
+ { &cmd_ggro_on, 4,0, &cmd_ggro_on, sizeof(cmd_ggro_on) },
+ { &cmd_gflags_on, 4, 0, &cmd_gflags_on, sizeof(cmd_sflags_on) },
+ { &cmd_gfeatures_max_on, sizeof(cmd_gfeatures_max_on.cmd),
+ 0, &cmd_gfeatures_max_on, sizeof(cmd_gfeatures_max_on) },
+ { 0, 0, 0, 0, 0 }
+};
+
+static const struct cmd_expect cmd_expect_set_features_min_off_min_on[] = {
+ { &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd),
+ 0, &cmd_gssetinfo, sizeof(cmd_gssetinfo) },
+ { &cmd_gstrings, sizeof(cmd_gstrings.cmd),
+ 0, &cmd_gstrings, sizeof(cmd_gstrings) },
+ { &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
+ { &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
+ { &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
+ { &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
+ { &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
+ { &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
+ { &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
+ { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
+ { &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off.cmd),
+ 0, &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off) },
+ { &cmd_sfeatures_min_on, sizeof(cmd_sfeatures_min_on),
+ ETHTOOL_F_WISH, 0, 0 },
+ { &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
+ { &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
+ { &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
+ { &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
+ { &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
+ { &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
+ { &cmd_ggro_on, 4,0, &cmd_ggro_on, sizeof(cmd_ggro_on) },
+ { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
+ { &cmd_gfeatures_min_on, sizeof(cmd_gfeatures_min_on.cmd),
+ 0, &cmd_gfeatures_min_on, sizeof(cmd_gfeatures_min_on) },
+ { 0, 0, 0, 0, 0 }
+};
+
+static const struct cmd_expect cmd_expect_set_features_min_off_min_off[] = {
+ { &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd),
+ 0, &cmd_gssetinfo, sizeof(cmd_gssetinfo) },
+ { &cmd_gstrings, sizeof(cmd_gstrings.cmd),
+ 0, &cmd_gstrings, sizeof(cmd_gstrings) },
+ { &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
+ { &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
+ { &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
+ { &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
+ { &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
+ { &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
+ { &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
+ { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
+ { &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off.cmd),
+ 0, &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off) },
+ { &cmd_sfeatures_min_off, sizeof(cmd_sfeatures_min_off), 0, 0, 0 },
+ { &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
+ { &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
+ { &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
+ { &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
+ { &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
+ { &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
+ { &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
+ { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
+ { &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off.cmd),
+ 0, &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off) },
+ { 0, 0, 0, 0, 0 }
+};
+
+static const struct cmd_expect cmd_expect_set_features_min_on_min_off[] = {
+ { &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd),
+ 0, &cmd_gssetinfo, sizeof(cmd_gssetinfo) },
+ { &cmd_gstrings, sizeof(cmd_gstrings.cmd),
+ 0, &cmd_gstrings, sizeof(cmd_gstrings) },
+ { &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
+ { &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
+ { &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
+ { &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
+ { &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
+ { &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
+ { &cmd_ggro_on, 4,0, &cmd_ggro_on, sizeof(cmd_ggro_on) },
+ { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
+ { &cmd_gfeatures_min_on, sizeof(cmd_gfeatures_min_on.cmd),
+ 0, &cmd_gfeatures_min_on, sizeof(cmd_gfeatures_min_on) },
+ { &cmd_sfeatures_min_off, sizeof(cmd_sfeatures_min_off), 0, 0, 0 },
+ { &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
+ { &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
+ { &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
+ { &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
+ { &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
+ { &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
+ { &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
+ { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
+ { &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off.cmd),
+ 0, &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off) },
+ { 0, 0, 0, 0, 0 }
+};
+
+static const struct cmd_expect cmd_expect_set_features_min_off_unsup_on[] = {
+ { &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd),
+ 0, &cmd_gssetinfo, sizeof(cmd_gssetinfo) },
+ { &cmd_gstrings, sizeof(cmd_gstrings.cmd),
+ 0, &cmd_gstrings, sizeof(cmd_gstrings) },
+ { &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
+ { &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
+ { &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
+ { &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
+ { &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
+ { &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
+ { &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
+ { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
+ { &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off.cmd),
+ 0, &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off) },
+ { &cmd_sfeatures_noop, sizeof(cmd_sfeatures_noop), 0, 0, 0 },
+ { &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
+ { &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
+ { &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
+ { &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
+ { &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
+ { &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
+ { &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
+ { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
+ { &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off.cmd),
+ 0, &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off) },
+ { 0, 0, 0, 0, 0 }
+};
+
+static const struct cmd_expect cmd_expect_set_features_ipv4_off_many_on[] = {
+ { &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd),
+ 0, &cmd_gssetinfo, sizeof(cmd_gssetinfo) },
+ { &cmd_gstrings, sizeof(cmd_gstrings.cmd),
+ 0, &cmd_gstrings, sizeof(cmd_gstrings) },
+ { &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
+ { &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
+ { &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
+ { &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
+ { &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
+ { &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
+ { &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
+ { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
+ { &cmd_gfeatures_ipv4_off, sizeof(cmd_gfeatures_ipv4_off.cmd),
+ 0, &cmd_gfeatures_ipv4_off, sizeof(cmd_gfeatures_ipv4_off) },
+ { &cmd_sfeatures_ipv4_on, sizeof(cmd_sfeatures_ipv4_on), 0, 0, 0 },
+ { &cmd_grxcsum_on, 4, 0, &cmd_grxcsum_on, sizeof(cmd_grxcsum_on) },
+ { &cmd_gtxcsum_on, 4, 0, &cmd_gtxcsum_on, sizeof(cmd_gtxcsum_on) },
+ { &cmd_gsg_on, 4, 0, &cmd_gsg_on, sizeof(cmd_gsg_on) },
+ { &cmd_gtso_on, 4, 0, &cmd_gtso_on, sizeof(cmd_gtso_on) },
+ { &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
+ { &cmd_ggso_on, 4, 0, &cmd_ggso_on, sizeof(cmd_ggso_on) },
+ { &cmd_ggro_on, 4,0, &cmd_ggro_on, sizeof(cmd_ggro_on) },
+ { &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
+ { &cmd_gfeatures_ipv4_on, sizeof(cmd_gfeatures_ipv4_on.cmd),
+ 0, &cmd_gfeatures_ipv4_on, sizeof(cmd_gfeatures_ipv4_on) },
+ { 0, 0, 0, 0, 0 }
+};
+
static struct test_case {
int rc;
const char *args;
const struct cmd_expect *expect;
} const test_cases[] = {
- { 0, "-k devname", cmd_expect_get_features_off },
+ { 0, "-k devname", cmd_expect_get_features_off_old },
{ 0, "-K devname rx off tx off sg off tso off ufo off gso off lro off rxvlan off txvlan off ntuple off rxhash off gro off",
- cmd_expect_set_features_off },
+ cmd_expect_set_features_off_old },
{ 0, "-K devname rx on tx on sg on tso on ufo on gso on lro on rxvlan on txvlan on ntuple on rxhash on gro on",
- cmd_expect_set_features_on },
+ cmd_expect_set_features_on_old },
+ { 1, "-K devname tx on sg on", cmd_expect_set_features_unsup_on_old },
+ { 0, "--show-offload devname", cmd_expect_get_features_min_off },
+ { 0, "--show-features devname", cmd_expect_get_features_max_on },
+ { 0, "-K devname rx on tx on sg on tso on ufo on gso on gro on",
+ cmd_expect_set_features_min_off_min_on },
+ { 0, "-K devname rx off tx off sg off tso off ufo off gso off gro off",
+ cmd_expect_set_features_min_off_min_off },
+ { 0, "-K devname rx off tx off sg off tso off ufo off gso off gro off",
+ cmd_expect_set_features_min_on_min_off },
+ { 1, "-K devname tx on sg on",
+ cmd_expect_set_features_min_off_unsup_on },
+ { 0, "--features devname rx on tx on sg on tso on gso on gro on",
+ cmd_expect_set_features_ipv4_off_many_on },
+ { 1, "-K devname rx foo", cmd_expect_get_strings_old },
+ { 1, "-K devname rx foo", cmd_expect_get_strings },
+ { 1, "--offload devname rx", cmd_expect_get_strings_old },
+ { 1, "--features devname rx", cmd_expect_get_strings },
+ { 1, "--features devname foo on", cmd_expect_get_strings_old },
+ { 1, "--offload devname foo on", cmd_expect_get_strings },
};
static int expect_matched;
--
1.7.7.6
--
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.
^ permalink raw reply related
* Re: [PATCH ethtool 0/7] Generic netdev features support
From: Stephen Hemminger @ 2012-06-02 0:45 UTC (permalink / raw)
To: Ben Hutchings; +Cc: netdev, Michał Mirosław, Mahesh Bandewar
In-Reply-To: <1338597227.2770.13.camel@bwh-desktop.uk.solarflarecom.com>
On Sat, 2 Jun 2012 01:33:47 +0100
Ben Hutchings <bhutchings@solarflare.com> wrote:
> This series adds support for the not-so-new generic netdev features
> ethtool API, along with some test infrastructure and test cases to check
> that it works with old and new kernel versions. I'm still not convinced
> that there are enough test cases, but I've held this back for too damn
> long already.
>
> I'd like to include these changes in an ethtool 3.4 release by the end
> of next week, so let me know if there's anything wrong with them.
>
> Ben.
Slightly off-topic, is anyone working on doing ethtool setting over netlink?
^ permalink raw reply
* Re: [PATCH net-next] tcp: avoid tx starvation by SYNACK packets
From: Dave Taht @ 2012-06-02 1:28 UTC (permalink / raw)
To: Eric Dumazet
Cc: Hans Schillstrom, netdev, Neal Cardwell, Tom Herbert,
Jesper Dangaard Brouer
In-Reply-To: <1338501397.2760.1395.camel@edumazet-glaptop>
On Thu, May 31, 2012 at 2:56 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> From: Eric Dumazet <edumazet@google.com>
>
> pfifo_fast being the default Qdisc, its pretty easy to fill it with
> SYNACK (small) packets while host is under SYNFLOOD attack.
>
> Packets of established TCP sessions are dropped and host appears almost
> dead.
>
> Avoid this problem assigning TC_PRIO_FILLER priority to SYNACK
> generated in SYNCOOKIE mode, so that these packets are enqueued into
> pfifo_fast band 2.
>
> Other packets, queued to band 0 or 1 are dequeued before any SYNACK
> packets waiting in band 2.
I am curious as to how well fq_codel survives an attack like this, without aid.
^ permalink raw reply
* Re: [PATCH ethtool 0/7] Generic netdev features support
From: Ben Hutchings @ 2012-06-02 1:31 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev, Michał Mirosław, Mahesh Bandewar
In-Reply-To: <20120601174517.100bf98f@nehalam.linuxnetplumber.net>
On Fri, 2012-06-01 at 17:45 -0700, Stephen Hemminger wrote:
> On Sat, 2 Jun 2012 01:33:47 +0100
> Ben Hutchings <bhutchings@solarflare.com> wrote:
>
> > This series adds support for the not-so-new generic netdev features
> > ethtool API, along with some test infrastructure and test cases to check
> > that it works with old and new kernel versions. I'm still not convinced
> > that there are enough test cases, but I've held this back for too damn
> > long already.
> >
> > I'd like to include these changes in an ethtool 3.4 release by the end
> > of next week, so let me know if there's anything wrong with them.
> >
> > Ben.
>
> Slightly off-topic, is anyone working on doing ethtool setting over netlink?
I'm not. I seem to remember you brought this up at netconf 2010 but I
don't remember what your motivation was. Were you thinking about being
able to monitor for changes, for example?
Ben.
--
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.
^ permalink raw reply
* Re: [PATCH net-next] tcp: avoid tx starvation by SYNACK packets
From: Eric Dumazet @ 2012-06-02 5:46 UTC (permalink / raw)
To: Dave Taht
Cc: Hans Schillstrom, netdev, Neal Cardwell, Tom Herbert,
Jesper Dangaard Brouer
In-Reply-To: <CAA93jw755V9kJ=P1gFsG2oafddhsebzfT3DuY5NX59GPpheOZg@mail.gmail.com>
On Fri, 2012-06-01 at 18:28 -0700, Dave Taht wrote:
> On Thu, May 31, 2012 at 2:56 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> > From: Eric Dumazet <edumazet@google.com>
> >
> > pfifo_fast being the default Qdisc, its pretty easy to fill it with
> > SYNACK (small) packets while host is under SYNFLOOD attack.
> >
> > Packets of established TCP sessions are dropped and host appears almost
> > dead.
> >
> > Avoid this problem assigning TC_PRIO_FILLER priority to SYNACK
> > generated in SYNCOOKIE mode, so that these packets are enqueued into
> > pfifo_fast band 2.
> >
> > Other packets, queued to band 0 or 1 are dequeued before any SYNACK
> > packets waiting in band 2.
>
> I am curious as to how well fq_codel survives an attack like this, without aid.
codel or fq_codel are not doing priority classification.
SYNACK will spread in all hash buckets and global queue limit can be
hit.
fq_codel wont protect you by itself, unless you use a hierarchy with one
"prio" and two or three "fq_codel".
^ permalink raw reply
* RE: [PATCH] tcp: do not create inetpeer on SYNACK message
From: Eric Dumazet @ 2012-06-02 6:56 UTC (permalink / raw)
To: Hans Schillström
Cc: netdev, Jesper Dangaard Brouer, David Miller, Neal Cardwell,
Tom Herbert
In-Reply-To: <C8A6796DE7C66C4ABCBC18106CB6C1CC164D13A516@ESESSCMS0356.eemea.ericsson.se>
On Fri, 2012-06-01 at 23:34 +0200, Hans Schillström wrote:
> It think we are on the right way now,
>
> Some results from one of our testers:
> before applying "reflect SYN queue_mapping into SYNACK"
>
> "(The latest one from Eric is not included. I am building with
> that one right now.)
> Results were that with the same number of SYN/s, load went down
> 30% on each of the three Cpus that were handling the SYNs.
> Great !!!"
>
I am not sure reflecting queue_mapping will help your workload, since
you specifically asked to your NIC to queue all SYN packets on one
single queue.
Eventually not relying on skb->queue_mapping but skb->rxhash to chose an
outgoing queue for the SYNACKS to not harm a single tx queue ?
Then it might be not needed, if the queue is dedicated to SYN and SYNACK
packets, since net_rx_action/net_tx_action should both dequeue 64
packets each round, in a round robin fashion.
(I had problems in a standard setup, where you can have a single cpu
(CPU0 in my case) servicing all NAPI interrupts, so with 16 queues, the
rx_action/tx_action ratio is 16/1 if all synack go to a single queue,
while SYN are distributed to all 16 rx queues)
> I'm looking forward to see the results of the latests patch.
>
> Then I think conntrack need a little shape up, like a "mini-conntrack"
> it is way to expensive to alloc a full "coontack for every SYN.
>
> I have a bunch of patches and ideas for that...
>
Cool ! the conntrack issue is a real one for sure.
Given the conntrack current requirement (being protected by a central
lock), I guess your best bet would be following setup :
One single CPU to handle all SYN packets.
Eventually not relying on skb->queue_mapping but skb->rxhash to chose an
outgoing queue for the SYNACKS to not harm a single tx queue.
> Thanks Eric for a great job
>
Thanks for giving testing results and ideas !
^ permalink raw reply
* [net 0/2][pull request] Intel Wired LAN Driver Update
From: Jeff Kirsher @ 2012-06-02 7:16 UTC (permalink / raw)
To: davem; +Cc: Jeff Kirsher, netdev, gospo, sassmann
This series contains fixes for e1000 and e1000e.
The following are changes since commit ad1be8d345416a794dea39761a374032aa471a76:
r8169: call netif_napi_del at errpaths and at driver unload
and are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net master
Bruce Allan (1):
e1000e: fix Rapid Start Technology support for i217
Sebastian Andrzej Siewior (1):
e1000: look into the page instead of skb->data for
e1000_tbi_adjust_stats()
drivers/net/ethernet/intel/e1000/e1000_main.c | 2 +-
drivers/net/ethernet/intel/e1000e/ich8lan.c | 18 +++++++++---------
2 files changed, 10 insertions(+), 10 deletions(-)
--
1.7.10.2
^ permalink raw reply
* [net 1/2] e1000: look into the page instead of skb->data for e1000_tbi_adjust_stats()
From: Jeff Kirsher @ 2012-06-02 7:16 UTC (permalink / raw)
To: davem; +Cc: Sebastian Andrzej Siewior, netdev, gospo, sassmann, Jeff Kirsher
In-Reply-To: <1338621416-22425-1-git-send-email-jeffrey.t.kirsher@intel.com>
From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
This is another fixup where the data is not transfered into buffer
addressed by skb->data but into a page.
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ethernet/intel/e1000/e1000_main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
index 95731c8..7483ca0 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -4080,7 +4080,7 @@ static bool e1000_clean_jumbo_rx_irq(struct e1000_adapter *adapter,
spin_lock_irqsave(&adapter->stats_lock,
irq_flags);
e1000_tbi_adjust_stats(hw, &adapter->stats,
- length, skb->data);
+ length, mapped);
spin_unlock_irqrestore(&adapter->stats_lock,
irq_flags);
length--;
--
1.7.10.2
^ permalink raw reply related
* [net 2/2] e1000e: fix Rapid Start Technology support for i217
From: Jeff Kirsher @ 2012-06-02 7:16 UTC (permalink / raw)
To: davem; +Cc: Bruce Allan, netdev, gospo, sassmann, Jeff Kirsher
In-Reply-To: <1338621416-22425-1-git-send-email-jeffrey.t.kirsher@intel.com>
From: Bruce Allan <bruce.w.allan@intel.com>
The definition of I217_PROXY_CTRL must use the BM_PHY_REG() macro instead
of the PHY_REG() macro for PHY page 800 register 70 since it is for a PHY
register greater than the maximum allowed by the latter macro, and fix a
typo setting the I217_MEMPWR register in e1000_suspend_workarounds_ich8lan.
Also for clarity, rename a few defines as bit definitions instead of masks.
Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ethernet/intel/e1000e/ich8lan.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c
index bbf70ba..238ab2f 100644
--- a/drivers/net/ethernet/intel/e1000e/ich8lan.c
+++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c
@@ -165,14 +165,14 @@
#define I217_EEE_100_SUPPORTED (1 << 1) /* 100BaseTx EEE supported */
/* Intel Rapid Start Technology Support */
-#define I217_PROXY_CTRL PHY_REG(BM_WUC_PAGE, 70)
+#define I217_PROXY_CTRL BM_PHY_REG(BM_WUC_PAGE, 70)
#define I217_PROXY_CTRL_AUTO_DISABLE 0x0080
#define I217_SxCTRL PHY_REG(BM_PORT_CTRL_PAGE, 28)
-#define I217_SxCTRL_MASK 0x1000
+#define I217_SxCTRL_ENABLE_LPI_RESET 0x1000
#define I217_CGFREG PHY_REG(772, 29)
-#define I217_CGFREG_MASK 0x0002
+#define I217_CGFREG_ENABLE_MTA_RESET 0x0002
#define I217_MEMPWR PHY_REG(772, 26)
-#define I217_MEMPWR_MASK 0x0010
+#define I217_MEMPWR_DISABLE_SMB_RELEASE 0x0010
/* Strapping Option Register - RO */
#define E1000_STRAP 0x0000C
@@ -4089,12 +4089,12 @@ void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw)
* power good.
*/
e1e_rphy_locked(hw, I217_SxCTRL, &phy_reg);
- phy_reg |= I217_SxCTRL_MASK;
+ phy_reg |= I217_SxCTRL_ENABLE_LPI_RESET;
e1e_wphy_locked(hw, I217_SxCTRL, phy_reg);
/* Disable the SMB release on LCD reset. */
e1e_rphy_locked(hw, I217_MEMPWR, &phy_reg);
- phy_reg &= ~I217_MEMPWR;
+ phy_reg &= ~I217_MEMPWR_DISABLE_SMB_RELEASE;
e1e_wphy_locked(hw, I217_MEMPWR, phy_reg);
}
@@ -4103,7 +4103,7 @@ void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw)
* Support
*/
e1e_rphy_locked(hw, I217_CGFREG, &phy_reg);
- phy_reg |= I217_CGFREG_MASK;
+ phy_reg |= I217_CGFREG_ENABLE_MTA_RESET;
e1e_wphy_locked(hw, I217_CGFREG, phy_reg);
release:
@@ -4176,7 +4176,7 @@ void e1000_resume_workarounds_pchlan(struct e1000_hw *hw)
ret_val = e1e_rphy_locked(hw, I217_MEMPWR, &phy_reg);
if (ret_val)
goto release;
- phy_reg |= I217_MEMPWR_MASK;
+ phy_reg |= I217_MEMPWR_DISABLE_SMB_RELEASE;
e1e_wphy_locked(hw, I217_MEMPWR, phy_reg);
/* Disable Proxy */
@@ -4186,7 +4186,7 @@ void e1000_resume_workarounds_pchlan(struct e1000_hw *hw)
ret_val = e1e_rphy_locked(hw, I217_CGFREG, &phy_reg);
if (ret_val)
goto release;
- phy_reg &= ~I217_CGFREG_MASK;
+ phy_reg &= ~I217_CGFREG_ENABLE_MTA_RESET;
e1e_wphy_locked(hw, I217_CGFREG, phy_reg);
release:
if (ret_val)
--
1.7.10.2
^ permalink raw reply related
* Network hangs on current git kernel
From: Markus Trippelsdorf @ 2012-06-02 8:25 UTC (permalink / raw)
To: netdev
I'm running the latest git kernel 3.4.0-09820-g86c47b7 and see periodic
network "hangs" on my machine.
These hangs mostly occur when I read nntp news articles. Every once in a
while the nntp client seems to take forever to fetch an article. During
these hangs I see packet losses:
% ping heise.de
PING heise.de (193.99.144.80) 56(84) bytes of data.
64 bytes from redirector.heise.de (193.99.144.80): icmp_req=2 ttl=246 time=22.2 ms
64 bytes from redirector.heise.de (193.99.144.80): icmp_req=4 ttl=246 time=22.3 ms
64 bytes from redirector.heise.de (193.99.144.80): icmp_req=8 ttl=246 time=21.9 ms
64 bytes from redirector.heise.de (193.99.144.80): icmp_req=12 ttl=246 time=23.4 ms
64 bytes from redirector.heise.de (193.99.144.80): icmp_req=15 ttl=246 time=22.5 ms
64 bytes from redirector.heise.de (193.99.144.80): icmp_req=19 ttl=246 time=22.9 ms
64 bytes from redirector.heise.de (193.99.144.80): icmp_req=21 ttl=246 time=21.6 ms <== Hang stops here
64 bytes from redirector.heise.de (193.99.144.80): icmp_req=22 ttl=246 time=23.2 ms
64 bytes from redirector.heise.de (193.99.144.80): icmp_req=23 ttl=246 time=23.4 ms
64 bytes from redirector.heise.de (193.99.144.80): icmp_req=24 ttl=246 time=22.9 ms
64 bytes from redirector.heise.de (193.99.144.80): icmp_req=25 ttl=246 time=22.9 ms
64 bytes from redirector.heise.de (193.99.144.80): icmp_req=26 ttl=246 time=22.5 ms
64 bytes from redirector.heise.de (193.99.144.80): icmp_req=27 ttl=246 time=22.4 ms
64 bytes from redirector.heise.de (193.99.144.80): icmp_req=28 ttl=246 time=22.4 ms
64 bytes from redirector.heise.de (193.99.144.80): icmp_req=29 ttl=246 time=22.0 ms
64 bytes from redirector.heise.de (193.99.144.80): icmp_req=30 ttl=246 time=22.4 ms
64 bytes from redirector.heise.de (193.99.144.80): icmp_req=31 ttl=246 time=22.0 ms
64 bytes from redirector.heise.de (193.99.144.80): icmp_req=32 ttl=246 time=22.0 ms
64 bytes from redirector.heise.de (193.99.144.80): icmp_req=33 ttl=246 time=22.0 ms
64 bytes from redirector.heise.de (193.99.144.80): icmp_req=34 ttl=246 time=21.8 ms
64 bytes from redirector.heise.de (193.99.144.80): icmp_req=35 ttl=246 time=23.1 ms
64 bytes from redirector.heise.de (193.99.144.80): icmp_req=36 ttl=246 time=22.4 ms
64 bytes from redirector.heise.de (193.99.144.80): icmp_req=37 ttl=246 time=23.2 ms
64 bytes from redirector.heise.de (193.99.144.80): icmp_req=38 ttl=246 time=22.3 ms
64 bytes from redirector.heise.de (193.99.144.80): icmp_req=39 ttl=246 time=32.2 ms
64 bytes from redirector.heise.de (193.99.144.80): icmp_req=40 ttl=246 time=22.5 ms
64 bytes from redirector.heise.de (193.99.144.80): icmp_req=41 ttl=246 time=22.6 ms
64 bytes from redirector.heise.de (193.99.144.80): icmp_req=42 ttl=246 time=23.7 ms
64 bytes from redirector.heise.de (193.99.144.80): icmp_req=43 ttl=246 time=22.7 ms
64 bytes from redirector.heise.de (193.99.144.80): icmp_req=44 ttl=246 time=27.4 ms
64 bytes from redirector.heise.de (193.99.144.80): icmp_req=45 ttl=246 time=22.2 ms
64 bytes from redirector.heise.de (193.99.144.80): icmp_req=46 ttl=246 time=22.5 ms
^C
--- heise.de ping statistics ---
46 packets transmitted, 32 received, 30% packet loss, time 45101ms
rtt min/avg/max/mdev = 21.613/23.021/32.210/1.924 ms
Sorry, if this all sounds somewhat vague. I will try to record a sysrq-w dump
in the future.
--
Markus
^ permalink raw reply
* Re: r8169: IO_PAGE_FAULT & netdev watchdog
From: Vincent Pelletier @ 2012-06-02 9:08 UTC (permalink / raw)
To: Francois Romieu; +Cc: netdev
In-Reply-To: <20120601125949.GA11973@electric-eye.fr.zoreil.com>
[-- Attachment #1: Type: Text/Plain, Size: 799 bytes --]
Le vendredi 01 juin 2012 14:59:49, Francois Romieu a écrit :
> You can apply the attached patch but it may not do much for your problem.
After failing to build the module alone in a way that it would accept loading
in debian-provided kernel, I fall back to building vanilla kernel + proposed
patches.
I first went for 3.4, but realised the patch you attached was already applied
there.
So I went with 3.3.7, and patch failed to apply, at least partly because 3.3.7
lacks "r8169: fix early queue wake-up."[1] . I solved the conflicts manually,
but I'm not sure of the result. Could you confirm attached patch might give
expected result ? Or should I stick to 3.4 and only test inlined patch ?
[1] ae1f23fb433ac0aaff8aeaa5a7b14348e9aa8277
Regards,
--
Vincent Pelletier
[-- Attachment #2: for_3.3.7.patch --]
[-- Type: text/x-patch, Size: 1564 bytes --]
--- drivers/net/ethernet/realtek/r8169.c.orig 2012-06-02 10:26:45.000000000 +0200
+++ drivers/net/ethernet/realtek/r8169.c 2012-06-02 10:58:37.000000000 +0200
@@ -62,8 +62,12 @@
#define R8169_MSG_DEFAULT \
(NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN)
-#define TX_BUFFS_AVAIL(tp) \
- (tp->dirty_tx + NUM_TX_DESC - tp->cur_tx - 1)
+#define TX_SLOTS_AVAIL(tp) \
+ (tp->dirty_tx + NUM_TX_DESC - tp->cur_tx)
+
+/* A skbuff with nr_frags needs nr_frags+1 entries in the tx queue */
+#define TX_FRAGS_READY_FOR(tp,nr_frags) \
+ (TX_SLOTS_AVAIL(tp) >= (nr_frags + 1))
/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
The RTL chips use a 64 element hash table based on the Ethernet CRC. */
@@ -5513,7 +5517,7 @@
u32 opts[2];
int frags;
- if (unlikely(TX_BUFFS_AVAIL(tp) < skb_shinfo(skb)->nr_frags)) {
+ if (unlikely(!TX_FRAGS_READY_FOR(tp, skb_shinfo(skb)->nr_frags))) {
netif_err(tp, drv, dev, "BUG! Tx Ring full when queue awake!\n");
goto err_stop_0;
}
@@ -5561,10 +5565,10 @@
RTL_W8(TxPoll, NPQ);
- if (TX_BUFFS_AVAIL(tp) < MAX_SKB_FRAGS) {
+ if (!TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS)) {
netif_stop_queue(dev);
smp_rmb();
- if (TX_BUFFS_AVAIL(tp) >= MAX_SKB_FRAGS)
+ if (TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS))
netif_wake_queue(dev);
}
@@ -5666,7 +5670,7 @@
tp->dirty_tx = dirty_tx;
smp_wmb();
if (netif_queue_stopped(dev) &&
- (TX_BUFFS_AVAIL(tp) >= MAX_SKB_FRAGS)) {
+ TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS)) {
netif_wake_queue(dev);
}
/*
^ permalink raw reply
* Re: 3.4-rc: NETDEV WATCHDOG: eth0 (r8169): transmit queue 0 timed out
From: Stefan Richter @ 2012-06-02 9:13 UTC (permalink / raw)
To: Francois Romieu; +Cc: netdev
In-Reply-To: <20120503204813.65468df7@stein>
On May 03 Stefan Richter wrote:
> On May 01 Francois Romieu wrote:
> [...]
> > Can you apply the patch below on top of current ethtool
> > (git://git.kernel.org/pub/scm/network/ethtool/ethtool.git) and see
> > if it is enough to compare the register dumps (ethtool -d eth0).
> [...]
> > This is a firmware free chipset anyway. Nothing strange in the interface
> > stats (ethtool -S eth0) ?
> >
> > You may have to narrow things. Can you check if the r8169.c at
> > 036dafa28da1e2565a8529de2ae663c37b7a0060 behaves the same ?
>
> I will follow up on this eventually, but it may take quite some time due
> to interfering work.
>
> Thank you for looking into it and giving directions,
I haven't had time to look further into it yet. Just two minor findings:
(a) After update from 3.4-rc5 to 3.4, the problem persisted.
(b) Later I noticed that silent file corruptions on FireWire disks happened
and happen under 3.4-rc5 and 3.4, so I reverted into 3.3.1 which fixed
that issue. Furthermore, since 6 days uptime of 3.3.1, the eth0 (r8169)
transmit queue time-out did never occur.
I have no idea whether the FireWire and networking issues might be somehow
connected, and I still lack time to investigate these issues (using Linux
only at home, not at work), but I will eventually get back to it.
--
Stefan Richter
-=====-===-- -==- ---=-
http://arcgraph.de/sr/
^ permalink raw reply
* Re: Network hangs on current git kernel
From: Eric Dumazet @ 2012-06-02 9:50 UTC (permalink / raw)
To: Markus Trippelsdorf; +Cc: netdev
In-Reply-To: <20120602082503.GC329@x4>
On Sat, 2012-06-02 at 10:25 +0200, Markus Trippelsdorf wrote:
> I'm running the latest git kernel 3.4.0-09820-g86c47b7 and see periodic
> network "hangs" on my machine.
>
> These hangs mostly occur when I read nntp news articles. Every once in a
> while the nntp client seems to take forever to fetch an article. During
> these hangs I see packet losses:
> --- heise.de ping statistics ---
> 46 packets transmitted, 32 received, 30% packet loss, time 45101ms
> rtt min/avg/max/mdev = 21.613/23.021/32.210/1.924 ms
>
> Sorry, if this all sounds somewhat vague. I will try to record a sysrq-w dump
> in the future.
>
For sure... its a bit vague.
Maybe tell us what NIC it is, that sort of things...
^ permalink raw reply
* Hello...
From: Western Union @ 2012-06-02 9:56 UTC (permalink / raw)
To: Recipients
We wish to inform you that We have sent $5000.00 USD already ,that was given to you by the European Union, as we are mandated to send you the total sum of 1000,000,00 USD through Western Union.send name,address, phone number.Processing your first payment of 5,000 USD.
Sign,
Rev. Clayton Bowie (Payment Officer)
Phone Number: Tel +(44) 7778 650 179
^ permalink raw reply
* Re: [PATCH v5 6/6 resend] net: sh_eth: use NAPI
From: Jan Ceuleers @ 2012-06-02 10:05 UTC (permalink / raw)
To: Shimoda, Yoshihiro; +Cc: netdev, SH-Linux
In-Reply-To: <4FC48589.6060009@renesas.com>
On 05/29/2012 10:15 AM, Shimoda, Yoshihiro wrote:
> @@ -1087,13 +1088,17 @@ static int sh_eth_rx(struct net_device *ndev)
> skb_reserve(skb, NET_IP_ALIGN);
> skb_put(skb, pkt_len);
> skb->protocol = eth_type_trans(skb, ndev);
> - netif_rx(skb);
> - ndev->stats.rx_packets++;
> - ndev->stats.rx_bytes += pkt_len;
> + if (netif_receive_skb(skb) == NET_RX_DROP) {
> + ndev->stats.rx_dropped++;
> + } else {
> + ndev->stats.rx_packets++;
> + ndev->stats.rx_bytes += pkt_len;
> + }
> }
> rxdesc->status |= cpu_to_edmac(mdp, RD_RACT);
> entry = (++mdp->cur_rx) % mdp->num_rx_ring;
> rxdesc = &mdp->rx_ring[entry];
> + (*work)++;
> }
>
> /* Refill the Rx ring buffers. */
Please forgive a newbie's question/comment; feel free to ignore if I'm
wasting your time. Particularly because it's about an aspect of the
driver that you're not changing in this patch. (And yes, I know that
you've been asked to sit on this patch series until net-next opens up
again).
I see that most users of netif_receive_skb() ignore its return value.
Some drivers (including this-one) do check it and use it to determine
whether counters should be updated. But looking at netif_receive_skb()
itself I see that there's counter infrastructure there already.
So why this in-driver set of counters, I wonder?
Thanks, Jan
^ permalink raw reply
* Re: r8169: IO_PAGE_FAULT & netdev watchdog
From: Francois Romieu @ 2012-06-02 10:56 UTC (permalink / raw)
To: Vincent Pelletier; +Cc: netdev
In-Reply-To: <201206021108.53551.plr.vincent@gmail.com>
Vincent Pelletier <plr.vincent@gmail.com> :
[...]
> So I went with 3.3.7, and patch failed to apply, at least partly because
> 3.3.7 lacks "r8169: fix early queue wake-up."[1].
And partly because the patch I sent included its content in the commit
message as well. :o/
> I solved the conflicts manually, but I'm not sure of the result. Could you
> confirm attached patch might give expected result ?
Yes.
> Or should I stick to 3.4 and only test inlined patch ?
If the inlined patch makes a difference, you should see it with 3.4.
My life is a bit easier when you work somewhere in the main branch
(or in davem's -next but it is not relevant for regression fixes).
--
Ueimor
^ permalink raw reply
* Re: Network hangs on current git kernel
From: Francois Romieu @ 2012-06-02 10:57 UTC (permalink / raw)
To: Markus Trippelsdorf; +Cc: Eric Dumazet, netdev
In-Reply-To: <1338630610.2760.1695.camel@edumazet-glaptop>
Eric Dumazet <eric.dumazet@gmail.com> :
> On Sat, 2012-06-02 at 10:25 +0200, Markus Trippelsdorf wrote:
[hang]
> Maybe tell us what NIC it is, that sort of things...
As well as 'ip -s link' and complete dmesg from boot.
Kernel .config may be.
--
Ueimor
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox