* Re: [PATCH net v5 4/6] Revert "net/ipv6: Bail early if user only wants cloned entries"
From: David Ahern @ 2019-06-18 14:51 UTC (permalink / raw)
To: Stefano Brivio, David Miller
Cc: Jianlin Shi, Wei Wang, Martin KaFai Lau, Eric Dumazet,
Matti Vaittinen, netdev
In-Reply-To: <6c7a9a747d667a581addca95370dd2532a55c015.1560827176.git.sbrivio@redhat.com>
On 6/18/19 7:20 AM, Stefano Brivio wrote:
> This reverts commit 08e814c9e8eb5a982cbd1e8f6bd255d97c51026f: as we
> are preparing to fix listing and dumping of IPv6 cached routes, we
> need to allow RTM_F_CLONED as a flag to match routes against while
> dumping them.
>
> Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
> ---
> v5: No changes
>
> v4: New patch
>
> net/ipv6/ip6_fib.c | 7 ++-----
> 1 file changed, 2 insertions(+), 5 deletions(-)
>
Reviewed-by: David Ahern <dsahern@gmail.com>
^ permalink raw reply
* Re: [PATCH net v5 0/6] Fix listing (IPv4, IPv6) and flushing (IPv6) of cached route exceptions
From: David Ahern @ 2019-06-18 14:51 UTC (permalink / raw)
To: Stefano Brivio, David Miller
Cc: Jianlin Shi, Wei Wang, Martin KaFai Lau, Eric Dumazet,
Matti Vaittinen, netdev
In-Reply-To: <cover.1560827176.git.sbrivio@redhat.com>
On 6/18/19 7:20 AM, Stefano Brivio wrote:
> For IPv6 cached routes, the commands 'ip -6 route list cache' and
> 'ip -6 route flush cache' don't work at all after route exceptions have
> been moved to a separate hash table in commit 2b760fcf5cfb ("ipv6: hook
> up exception table to store dst cache").
>
> For IPv4 cached routes, the command 'ip route list cache' has also
> stopped working in kernel 3.5 after commit 4895c771c7f0 ("ipv4: Add FIB
> nexthop exceptions.") introduced storage for route exceptions as a
> separate entity.
>
> Fix this by allowing userspace to clearly request cached routes with
> the RTM_F_CLONED flag used as a filter (in conjuction with strict
> checking) and by retrieving and dumping cached routes if requested.
>
> If strict checking is not requested (iproute2 < 5.0.0), we don't have a
> way to consistently filter results on other selectors (e.g. on tables),
> so skip filtering entirely and dump both regular routes and exceptions.
>
> I'm submitting this for net as these changes fix rather relevant
> breakages. However, the scope might be a bit broad, and said breakages
> have been introduced 7 and 2 years ago, respectively, for IPv4 and IPv6.
> Let me know if I should rebase this on net-next instead.
>
> For IPv4, cache flushing uses a completely different mechanism, so it
> wasn't affected. Listing of exception routes (modified routes pre-3.5) was
> tested against these versions of kernel and iproute2:
>
Changing the dump code has been notoriously tricky to get right in one
go, no matter how much testing you have done. Given that I think this
should go to net-next first and once it proves ok there we can look at a
backport to stable trees.
^ permalink raw reply
* [PATCH iproute2 v2 3/3] netns: make netns_{save,restore} static
From: Matteo Croce @ 2019-06-18 14:49 UTC (permalink / raw)
To: netdev; +Cc: Stephen Hemminger, David Ahern, Andrea Claudi
In-Reply-To: <20190618144935.31405-1-mcroce@redhat.com>
The netns_{save,restore} functions are only used in ipnetns.c now, since
the restore is not needed anymore after the netns exec command.
Move them in ipnetns.c, and make them static.
Signed-off-by: Matteo Croce <mcroce@redhat.com>
---
include/namespace.h | 2 --
ip/ip.c | 1 -
ip/ipnetns.c | 31 +++++++++++++++++++++++++++++++
lib/namespace.c | 31 -------------------------------
4 files changed, 31 insertions(+), 34 deletions(-)
diff --git a/include/namespace.h b/include/namespace.h
index 89cdda11..e47f9b5d 100644
--- a/include/namespace.h
+++ b/include/namespace.h
@@ -49,8 +49,6 @@ static inline int setns(int fd, int nstype)
}
#endif /* HAVE_SETNS */
-void netns_save(void);
-void netns_restore(void);
int netns_switch(char *netns);
int netns_get_fd(const char *netns);
int netns_foreach(int (*func)(char *nsname, void *arg), void *arg);
diff --git a/ip/ip.c b/ip/ip.c
index 49b3aa49..b71ae816 100644
--- a/ip/ip.c
+++ b/ip/ip.c
@@ -158,7 +158,6 @@ static int batch(const char *name)
if (!force)
break;
}
- netns_restore();
}
if (line)
free(line);
diff --git a/ip/ipnetns.c b/ip/ipnetns.c
index 58655676..a883f210 100644
--- a/ip/ipnetns.c
+++ b/ip/ipnetns.c
@@ -45,6 +45,7 @@ static int usage(void)
static struct rtnl_handle rtnsh = { .fd = -1 };
static int have_rtnl_getnsid = -1;
+static int saved_netns = -1;
static int ipnetns_accept_msg(struct rtnl_ctrl_data *ctrl,
struct nlmsghdr *n, void *arg)
@@ -635,6 +636,33 @@ static int create_netns_dir(void)
return 0;
}
+/* Obtain a FD for the current namespace, so we can reenter it later */
+static void netns_save(void)
+{
+ if (saved_netns != -1)
+ return;
+
+ saved_netns = open("/proc/self/ns/net", O_RDONLY | O_CLOEXEC);
+ if (saved_netns == -1) {
+ perror("Cannot open init namespace");
+ exit(1);
+ }
+}
+
+static void netns_restore(void)
+{
+ if (saved_netns == -1)
+ return;
+
+ if (setns(saved_netns, CLONE_NEWNET)) {
+ perror("setns");
+ exit(1);
+ }
+
+ close(saved_netns);
+ saved_netns = -1;
+}
+
static int netns_add(int argc, char **argv, bool create)
{
/* This function creates a new network namespace and
@@ -728,9 +756,12 @@ static int netns_add(int argc, char **argv, bool create)
proc_path, netns_path, strerror(errno));
goto out_delete;
}
+ netns_restore();
+
return 0;
out_delete:
if (create) {
+ netns_restore();
netns_delete(argc, argv);
} else if (unlink(netns_path) < 0) {
fprintf(stderr, "Cannot remove namespace file \"%s\": %s\n",
diff --git a/lib/namespace.c b/lib/namespace.c
index a2aea57a..06ae0a48 100644
--- a/lib/namespace.c
+++ b/lib/namespace.c
@@ -15,35 +15,6 @@
#include "utils.h"
#include "namespace.h"
-static int saved_netns = -1;
-
-/* Obtain a FD for the current namespace, so we can reenter it later */
-void netns_save(void)
-{
- if (saved_netns != -1)
- return;
-
- saved_netns = open("/proc/self/ns/net", O_RDONLY | O_CLOEXEC);
- if (saved_netns == -1) {
- perror("Cannot open init namespace");
- exit(1);
- }
-}
-
-void netns_restore(void)
-{
- if (saved_netns == -1)
- return;
-
- if (setns(saved_netns, CLONE_NEWNET)) {
- perror("setns");
- exit(1);
- }
-
- close(saved_netns);
- saved_netns = -1;
-}
-
static void bind_etc(const char *name)
{
char etc_netns_path[sizeof(NETNS_ETC_DIR) + NAME_MAX];
@@ -90,8 +61,6 @@ int netns_switch(char *name)
return -1;
}
- netns_save();
-
if (setns(netns, CLONE_NEWNET) < 0) {
fprintf(stderr, "setting the network namespace \"%s\" failed: %s\n",
name, strerror(errno));
--
2.21.0
^ permalink raw reply related
* [PATCH iproute2 v2 2/3] ip vrf: use hook to change VRF in the child
From: Matteo Croce @ 2019-06-18 14:49 UTC (permalink / raw)
To: netdev; +Cc: Stephen Hemminger, David Ahern, Andrea Claudi
In-Reply-To: <20190618144935.31405-1-mcroce@redhat.com>
On vrf exec, reset the VRF associations in the child process, via the
new hook added to cmd_exec(). In this way, the parent doesn't have to
reset the VRF associations before spawning other processes.
Signed-off-by: Matteo Croce <mcroce@redhat.com>
---
ip/ipvrf.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/ip/ipvrf.c b/ip/ipvrf.c
index 2b019c6c..43366f6e 100644
--- a/ip/ipvrf.c
+++ b/ip/ipvrf.c
@@ -442,6 +442,13 @@ out:
return rc;
}
+static int do_switch(void *arg)
+{
+ char *vrf = arg;
+
+ return vrf_switch(vrf);
+}
+
static int ipvrf_exec(int argc, char **argv)
{
if (argc < 1) {
@@ -453,10 +460,7 @@ static int ipvrf_exec(int argc, char **argv)
return -1;
}
- if (vrf_switch(argv[0]))
- return -1;
-
- return -cmd_exec(argv[1], argv + 1, !!batch_mode, NULL, NULL);
+ return -cmd_exec(argv[1], argv + 1, !!batch_mode, do_switch, argv[0]);
}
/* reset VRF association of current process to default VRF;
--
2.21.0
^ permalink raw reply related
* [PATCH iproute2 v2 1/3] netns: switch netns in the child when executing commands
From: Matteo Croce @ 2019-06-18 14:49 UTC (permalink / raw)
To: netdev; +Cc: Stephen Hemminger, David Ahern, Andrea Claudi
In-Reply-To: <20190618144935.31405-1-mcroce@redhat.com>
'ip netns exec' changes the current netns just before executing a child
process, and restores it after forking. This is needed if we're running
in batch or do_all mode.
Some cleanups must be done both in the parent and in the child: the
parent must restore the previous netns, while the child must reset any
VRF association.
Unfortunately, if do_all is set, the VRF are not reset in the child, and
the spawned processes are started with the wrong VRF context. This can
be triggered with this script:
# ip -b - <<-'EOF'
link add type vrf table 100
link set vrf0 up
link add type dummy
link set dummy0 vrf vrf0 up
netns add ns1
EOF
# ip -all -b - <<-'EOF'
vrf exec vrf0 true
netns exec setsid -f sleep 1h
EOF
# ip vrf pids vrf0
314 sleep
# ps 314
PID TTY STAT TIME COMMAND
314 ? Ss 0:00 sleep 1h
Refactor cmd_exec() and pass to it a function pointer which is called in
the child before the final exec. In the netns exec case the function just
resets the VRF and switches netns.
Doing it in the child is less error prone and safer, because the parent
environment is always kept unaltered.
After this refactor some utility functions became unused, so remove them.
Signed-off-by: Matteo Croce <mcroce@redhat.com>
---
v1->v2:
just restored the vrf_reset call before the exec
include/utils.h | 6 ++----
ip/ipnetns.c | 30 ++++++++++++++++--------------
ip/ipvrf.c | 2 +-
lib/exec.c | 7 ++++++-
lib/utils.c | 27 ---------------------------
5 files changed, 25 insertions(+), 47 deletions(-)
diff --git a/include/utils.h b/include/utils.h
index 8a9c3020..927fdc17 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -294,14 +294,12 @@ extern int cmdlineno;
ssize_t getcmdline(char **line, size_t *len, FILE *in);
int makeargs(char *line, char *argv[], int maxargs);
-int do_each_netns(int (*func)(char *nsname, void *arg), void *arg,
- bool show_label);
-
char *int_to_str(int val, char *buf);
int get_guid(__u64 *guid, const char *arg);
int get_real_family(int rtm_type, int rtm_family);
-int cmd_exec(const char *cmd, char **argv, bool do_fork);
+int cmd_exec(const char *cmd, char **argv, bool do_fork,
+ int (*setup)(void *), void *arg);
int make_path(const char *path, mode_t mode);
char *find_cgroup2_mount(void);
int get_command_name(const char *pid, char *comm, size_t len);
diff --git a/ip/ipnetns.c b/ip/ipnetns.c
index 8ead0c4c..58655676 100644
--- a/ip/ipnetns.c
+++ b/ip/ipnetns.c
@@ -396,11 +396,24 @@ static int netns_list(int argc, char **argv)
return 0;
}
+static int do_switch(void *arg)
+{
+ char *netns = arg;
+
+ /* we just changed namespaces. clear any vrf association
+ * with prior namespace before exec'ing command
+ */
+ vrf_reset();
+
+ return netns_switch(netns);
+}
+
static int on_netns_exec(char *nsname, void *arg)
{
char **argv = arg;
- cmd_exec(argv[1], argv + 1, true);
+ printf("\nnetns: %s\n", nsname);
+ cmd_exec(argv[0], argv, true, do_switch, nsname);
return 0;
}
@@ -409,8 +422,6 @@ static int netns_exec(int argc, char **argv)
/* Setup the proper environment for apps that are not netns
* aware, and execute a program in that environment.
*/
- const char *cmd;
-
if (argc < 1 && !do_all) {
fprintf(stderr, "No netns name specified\n");
return -1;
@@ -421,22 +432,13 @@ static int netns_exec(int argc, char **argv)
}
if (do_all)
- return do_each_netns(on_netns_exec, --argv, 1);
-
- if (netns_switch(argv[0]))
- return -1;
-
- /* we just changed namespaces. clear any vrf association
- * with prior namespace before exec'ing command
- */
- vrf_reset();
+ return netns_foreach(on_netns_exec, argv);
/* ip must return the status of the child,
* but do_cmd() will add a minus to this,
* so let's add another one here to cancel it.
*/
- cmd = argv[1];
- return -cmd_exec(cmd, argv + 1, !!batch_mode);
+ return -cmd_exec(argv[1], argv + 1, !!batch_mode, do_switch, argv[0]);
}
static int is_pid(const char *str)
diff --git a/ip/ipvrf.c b/ip/ipvrf.c
index a13cf653..2b019c6c 100644
--- a/ip/ipvrf.c
+++ b/ip/ipvrf.c
@@ -456,7 +456,7 @@ static int ipvrf_exec(int argc, char **argv)
if (vrf_switch(argv[0]))
return -1;
- return -cmd_exec(argv[1], argv + 1, !!batch_mode);
+ return -cmd_exec(argv[1], argv + 1, !!batch_mode, NULL, NULL);
}
/* reset VRF association of current process to default VRF;
diff --git a/lib/exec.c b/lib/exec.c
index eb36b59d..9b1c8f4a 100644
--- a/lib/exec.c
+++ b/lib/exec.c
@@ -5,8 +5,10 @@
#include <unistd.h>
#include "utils.h"
+#include "namespace.h"
-int cmd_exec(const char *cmd, char **argv, bool do_fork)
+int cmd_exec(const char *cmd, char **argv, bool do_fork,
+ int (*setup)(void *), void *arg)
{
fflush(stdout);
if (do_fork) {
@@ -34,6 +36,9 @@ int cmd_exec(const char *cmd, char **argv, bool do_fork)
}
}
+ if (setup && setup(arg))
+ return -1;
+
if (execvp(cmd, argv) < 0)
fprintf(stderr, "exec of \"%s\" failed: %s\n",
cmd, strerror(errno));
diff --git a/lib/utils.c b/lib/utils.c
index a81c0700..be0f11b0 100644
--- a/lib/utils.c
+++ b/lib/utils.c
@@ -1418,33 +1418,6 @@ void print_nlmsg_timestamp(FILE *fp, const struct nlmsghdr *n)
fprintf(fp, "Timestamp: %s %lu us\n", tstr, usecs);
}
-static int on_netns(char *nsname, void *arg)
-{
- struct netns_func *f = arg;
-
- if (netns_switch(nsname))
- return -1;
-
- return f->func(nsname, f->arg);
-}
-
-static int on_netns_label(char *nsname, void *arg)
-{
- printf("\nnetns: %s\n", nsname);
- return on_netns(nsname, arg);
-}
-
-int do_each_netns(int (*func)(char *nsname, void *arg), void *arg,
- bool show_label)
-{
- struct netns_func nsf = { .func = func, .arg = arg };
-
- if (show_label)
- return netns_foreach(on_netns_label, &nsf);
-
- return netns_foreach(on_netns, &nsf);
-}
-
char *int_to_str(int val, char *buf)
{
sprintf(buf, "%d", val);
--
2.21.0
^ permalink raw reply related
* [PATCH iproute2 v2 0/3] refactor the cmd_exec()
From: Matteo Croce @ 2019-06-18 14:49 UTC (permalink / raw)
To: netdev; +Cc: Stephen Hemminger, David Ahern, Andrea Claudi
Refactor the netns and ipvrf code so less steps are needed to exec commands
in a netns or a VRF context.
Also remove some code which became dead. bloat-o-meter shows a tiny saving.
Matteo Croce (3):
netns: switch netns in the child when executing commands
ip vrf: use hook to change VRF in the child
netns: make netns_{save,restore} static
include/namespace.h | 2 --
include/utils.h | 6 ++---
ip/ip.c | 1 -
ip/ipnetns.c | 61 ++++++++++++++++++++++++++++++++++-----------
ip/ipvrf.c | 12 ++++++---
lib/exec.c | 7 +++++-
lib/namespace.c | 31 -----------------------
lib/utils.c | 27 --------------------
8 files changed, 63 insertions(+), 84 deletions(-)
--
2.21.0
^ permalink raw reply
* Re: [PATCH net v5 2/6] ipv4/fib_frontend: Allow RTM_F_CLONED flag to be used for filtering
From: David Ahern @ 2019-06-18 14:49 UTC (permalink / raw)
To: Stefano Brivio, David Miller
Cc: Jianlin Shi, Wei Wang, Martin KaFai Lau, Eric Dumazet,
Matti Vaittinen, netdev
In-Reply-To: <4c351295757f82ddc83f6e433150fedda5517fe1.1560827176.git.sbrivio@redhat.com>
On 6/18/19 7:20 AM, Stefano Brivio wrote:
> This functionally reverts the check introduced by commit
> e8ba330ac0c5 ("rtnetlink: Update fib dumps for strict data checking")
> as modified by commit e4e92fb160d7 ("net/ipv4: Bail early if user only
> wants prefix entries").
>
> As we are preparing to fix listing of IPv4 cached routes, we need to
> give userspace a way to request them.
>
> Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
> ---
Reviewed-by: David Ahern <dsahern@gmail.com>
^ permalink raw reply
* Re: [PATCH net v5 1/6] fib_frontend, ip6_fib: Select routes or exceptions dump from RTM_F_CLONED
From: David Ahern @ 2019-06-18 14:49 UTC (permalink / raw)
To: Stefano Brivio, David Miller
Cc: Jianlin Shi, Wei Wang, Martin KaFai Lau, Eric Dumazet,
Matti Vaittinen, netdev
In-Reply-To: <91775eb67dfb3ab39576b421c98c84f74fe11594.1560827176.git.sbrivio@redhat.com>
On 6/18/19 7:20 AM, Stefano Brivio wrote:
> The following patches add back the ability to dump IPv4 and IPv6 exception
> routes, and we need to allow selection of regular routes or exceptions.
>
> Use RTM_F_CLONED as filter to decide whether to dump routes or exceptions:
> iproute2 passes it in dump requests (except for IPv6 cache flush requests,
> this will be fixed in iproute2) and this used to work as long as
> exceptions were stored directly in the FIB, for both IPv4 and IPv6.
>
> Caveat: if strict checking is not requested (that is, if the dump request
> doesn't go through ip_valid_fib_dump_req()), we can't filter on protocol,
> tables or route types.
>
> In this case, filtering on RTM_F_CLONED would be inconsistent: we would
> fix 'ip route list cache' by returning exception routes and at the same
> time introduce another bug in case another selector is present, e.g. on
> 'ip route list cache table main' we would return all exception routes,
> without filtering on tables.
>
> Keep this consistent by applying no filters at all, and dumping both
> routes and exceptions, if strict checking is not requested. iproute2
> currently filters results anyway, and no unwanted results will be
> presented to the user. The kernel will just dump more data than needed.
>
> v5: New patch: add dump_routes and dump_exceptions flags in filter and
> simply clear the unwanted one if strict checking is enabled, don't
> ignore NLM_F_MATCH and don't set filter_set if NLM_F_MATCH is set.
> Skip filtering altogether if no strict checking is requested:
> selecting routes or exceptions only would be inconsistent with the
> fact we can't filter on tables.
>
> Suggested-by: David Ahern <dsahern@gmail.com>
> Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
> ---
> include/net/ip_fib.h | 2 ++
> net/ipv4/fib_frontend.c | 8 +++++++-
> net/ipv6/ip6_fib.c | 3 ++-
> 3 files changed, 11 insertions(+), 2 deletions(-)
>
Reviewed-by: David Ahern <dsahern@gmail.com>
^ permalink raw reply
* Re: [PATCH net v5 3/6] ipv4: Dump route exceptions if requested
From: David Ahern @ 2019-06-18 14:48 UTC (permalink / raw)
To: Stefano Brivio, David Miller
Cc: Jianlin Shi, Wei Wang, Martin KaFai Lau, Eric Dumazet,
Matti Vaittinen, netdev
In-Reply-To: <106687f38b1eaf957f4ff2bad343519231815482.1560827176.git.sbrivio@redhat.com>
On 6/18/19 7:20 AM, Stefano Brivio wrote:
> diff --git a/include/net/route.h b/include/net/route.h
> index 065b47754f05..f0d0086e76ce 100644
> --- a/include/net/route.h
> +++ b/include/net/route.h
> @@ -221,6 +221,9 @@ void ip_rt_get_source(u8 *src, struct sk_buff *skb, struct rtable *rt);
> struct rtable *rt_dst_alloc(struct net_device *dev,
> unsigned int flags, u16 type,
> bool nopolicy, bool noxfrm, bool will_cache);
> +int rt_fill_info(struct net *net, __be32 dst, __be32 src, struct rtable *rt,
> + u32 table_id, struct flowi4 *fl4, struct sk_buff *skb,
> + u32 portid, u32 seq);
>
> struct in_ifaddr;
> void fib_add_ifaddr(struct in_ifaddr *);
> diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
> index 868c74771fa9..a00408827ae8 100644
> --- a/net/ipv4/fib_trie.c
> +++ b/net/ipv4/fib_trie.c
> @@ -2000,28 +2000,92 @@ void fib_free_table(struct fib_table *tb)
> call_rcu(&tb->rcu, __trie_free_rcu);
> }
>
> +static int fib_dump_fnhe_from_leaf(struct fib_alias *fa, struct sk_buff *skb,
> + struct netlink_callback *cb,
> + int *fa_index, int fa_start)
> +{
> + struct net *net = sock_net(cb->skb->sk);
> + struct fib_info *fi = fa->fa_info;
> + struct fnhe_hash_bucket *bucket;
> + struct fib_nh_common *nhc;
> + int i, genid;
> +
> + if (!fi || fi->fib_flags & RTNH_F_DEAD)
> + return 0;
> +
> + nhc = fib_info_nhc(fi, 0);
This should be a loop over fi->fib_nhs for net:
for (i = 0; i < fi->fib_nhs; i++) {
nhc = fib_info_nhc(fi, 0);
...
and a loop over fib_info_num_path(fi) for net-next:
for (i = 0; i < fib_info_num_path(fi); i++) {
nhc = fib_info_nhc(fi, 0);
...
> + if (nhc->nhc_flags & RTNH_F_DEAD)
> + return 0;
And then the loop over the exception bucket could be a helper in route.c
in which case you don't need to export rt_fill_info and nhc_exceptions
code does not spread to fib_trie.c
> +
> + bucket = rcu_dereference(nhc->nhc_exceptions);
> + if (!bucket)
> + return 0;
> +
> + genid = fnhe_genid(net);
> +
> + for (i = 0; i < FNHE_HASH_SIZE; i++) {
> + struct fib_nh_exception *fnhe;
> +
> + for (fnhe = rcu_dereference(bucket[i].chain); fnhe;
> + fnhe = rcu_dereference(fnhe->fnhe_next)) {
> + struct flowi4 fl4 = {};
rather than pass an empty flow struct, update rt_fill_info to handle a
NULL fl4; it's only a few checks.
> + struct rtable *rt;
> + int err;
> +
> + if (*fa_index < fa_start)
> + goto next;
> +
> + if (fnhe->fnhe_genid != genid)
> + goto next;
> +
> + if (fnhe->fnhe_expires &&
> + time_after(jiffies, fnhe->fnhe_expires))
> + goto next;
> +
> + rt = rcu_dereference(fnhe->fnhe_rth_input);
> + if (!rt)
> + rt = rcu_dereference(fnhe->fnhe_rth_output);
> + if (!rt)
> + goto next;
> +
> + err = rt_fill_info(net, fnhe->fnhe_daddr, 0, rt,
> + fa->tb_id, &fl4, skb,
> + NETLINK_CB(cb->skb).portid,
> + cb->nlh->nlmsg_seq);
> + if (err)
> + return err;
> +next:
> + (*fa_index)++;
> + }
> + }
> +
> + return 0;
> +}
> +
^ permalink raw reply
* Re: [PATCH] netfilter: nft_paylaod: add base type NFT_PAYLOAD_LL_HEADER_NO_TAG
From: wenxu @ 2019-06-18 14:27 UTC (permalink / raw)
To: Florian Westphal; +Cc: Pablo Neira Ayuso, netfilter-devel, netdev
In-Reply-To: <20190618093748.dydodhngydfcfmeh@breakpoint.cc>
在 2019/6/18 17:37, Florian Westphal 写道:
> wenxu <wenxu@ucloud.cn> wrote:
>> On 6/18/2019 6:42 AM, Florian Westphal wrote:
>>> Pablo Neira Ayuso <pablo@netfilter.org> wrote:
>>>>> Subject: Change bridge l3 dependency to meta protocol
>>>>>
>>>>> This examines skb->protocol instead of ethernet header type, which
>>>>> might be different when vlan is involved.
>>>>>
>>>>> + if (ctx->pctx.family == NFPROTO_BRIDGE && desc == &proto_eth) {
>>>>> + if (expr->payload.desc == &proto_ip ||
>>>>> + expr->payload.desc == &proto_ip6)
>>>>> + desc = &proto_metaeth;
>>>>> + }i
>>>> Is this sufficient to restrict the matching? Is this still buggy from
>>>> ingress?
>>> This is what netdev family uses as well (skb->protocol i mean).
>>> I'm not sure it will work for output however (haven't checked).
>>>
>>>> I wonder if an explicit NFT_PAYLOAD_CHECK_VLAN flag would be useful in
>>>> the kernel, if so we could rename NFTA_PAYLOAD_CSUM_FLAGS to
>>>> NFTA_PAYLOAD_FLAGS and place it there. Just an idea.
>>> Another unresolved issue is presence of multiple vlan tags, so we might
>>> have to add yet another meta key to retrieve the l3 protocol in use
>> Maybe add a l3proto meta key can handle the multiple vlan tags case with the l3proto dependency. It
>> should travese all the vlan tags and find the real l3 proto.
> Yes, something like this.
>
> We also need to audit netdev and bridge expressions (reject is known broken)
> to handle vlans properly.
>
> Still, switching nft to prefer skb->protocol instead of eth_hdr->type
> for dependencies would be good as this doesn't need kernel changes and solves
> the immediate problem of 'ip ...' not matching in case of vlan.
>
> If you have time, could you check if using skb->protocol works for nft
> bridge in output, i.e. does 'nft ip protocol icmp' match when its used
> from bridge output path with meta protocol dependency with and without
> vlan in use?
I just check the kernel codes and test with the output chain, the meta protocol dependency can
also work in the outpu chain.
But this patch can't resolve the multiple vlan tags, It need another meta l3proto which do care about
how many vlan tags in the frame.
^ permalink raw reply
* [PATCH][V2][next] netfilter: synproxy: ensure zero is returned on non-error return path
From: Colin King @ 2019-06-18 14:22 UTC (permalink / raw)
To: Pablo Neira Ayuso, Jozsef Kadlecsik, Florian Westphal,
David S . Miller, netfilter-devel, coreteam, netdev
Cc: kernel-janitors, linux-kernel
From: Colin Ian King <colin.king@canonical.com>
Currently functions nf_synproxy_{ipc4|ipv6}_init return an uninitialized
garbage value in variable ret on a successful return. Fix this by
returning zero on success.
Addresses-Coverity: ("Uninitialized scalar variable")
Fixes: d7f9b2f18eae ("netfilter: synproxy: extract SYNPROXY infrastructure from {ipt, ip6t}_SYNPROXY")
Signed-off-by: Colin Ian King <colin.king@canonical.com>
---
net/netfilter/nf_synproxy_core.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/netfilter/nf_synproxy_core.c b/net/netfilter/nf_synproxy_core.c
index 50677285f82e..7bf5202e3222 100644
--- a/net/netfilter/nf_synproxy_core.c
+++ b/net/netfilter/nf_synproxy_core.c
@@ -798,7 +798,7 @@ int nf_synproxy_ipv4_init(struct synproxy_net *snet, struct net *net)
}
snet->hook_ref4++;
- return err;
+ return 0;
}
EXPORT_SYMBOL_GPL(nf_synproxy_ipv4_init);
@@ -1223,7 +1223,7 @@ nf_synproxy_ipv6_init(struct synproxy_net *snet, struct net *net)
}
snet->hook_ref6++;
- return err;
+ return 0;
}
EXPORT_SYMBOL_GPL(nf_synproxy_ipv6_init);
--
2.20.1
^ permalink raw reply related
* Re: [PATCH][next] netfilter: synproxy: ensure zero is returned on non-error return path
From: Colin Ian King @ 2019-06-18 14:15 UTC (permalink / raw)
To: Pablo Neira Ayuso, Jozsef Kadlecsik, Florian Westphal,
David S . Miller, netfilter-devel, coreteam, netdev
Cc: kernel-janitors, linux-kernel
In-Reply-To: <20190618141319.14961-1-colin.king@canonical.com>
On 18/06/2019 15:13, Colin King wrote:
> From: Colin Ian King <colin.king@canonical.com>
>
> Currently function nf_synproxy_ipv6_init returns an uninitialized
> garbage value in variable ret on a successful return. Fix this by
> returning zero on success.
>
> Addresses-Coverity: ("Uninitialized scalar variable")
> Fixes: d7f9b2f18eae ("netfilter: synproxy: extract SYNPROXY infrastructure from {ipt, ip6t}_SYNPROXY")
> Signed-off-by: Colin Ian King <colin.king@canonical.com>
> ---
> net/netfilter/nf_synproxy_core.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/net/netfilter/nf_synproxy_core.c b/net/netfilter/nf_synproxy_core.c
> index 50677285f82e..701f880d01e6 100644
> --- a/net/netfilter/nf_synproxy_core.c
> +++ b/net/netfilter/nf_synproxy_core.c
> @@ -1223,7 +1223,7 @@ nf_synproxy_ipv6_init(struct synproxy_net *snet, struct net *net)
> }
>
> snet->hook_ref6++;
> - return err;
> + return 0;
> }
> EXPORT_SYMBOL_GPL(nf_synproxy_ipv6_init);
>
>
Scratch that, I've noticed the same issue in the ipv4 code too. I'll
send a V2.
^ permalink raw reply
* [PATCH][next] netfilter: synproxy: ensure zero is returned on non-error return path
From: Colin King @ 2019-06-18 14:13 UTC (permalink / raw)
To: Pablo Neira Ayuso, Jozsef Kadlecsik, Florian Westphal,
David S . Miller, netfilter-devel, coreteam, netdev
Cc: kernel-janitors, linux-kernel
From: Colin Ian King <colin.king@canonical.com>
Currently function nf_synproxy_ipv6_init returns an uninitialized
garbage value in variable ret on a successful return. Fix this by
returning zero on success.
Addresses-Coverity: ("Uninitialized scalar variable")
Fixes: d7f9b2f18eae ("netfilter: synproxy: extract SYNPROXY infrastructure from {ipt, ip6t}_SYNPROXY")
Signed-off-by: Colin Ian King <colin.king@canonical.com>
---
net/netfilter/nf_synproxy_core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/netfilter/nf_synproxy_core.c b/net/netfilter/nf_synproxy_core.c
index 50677285f82e..701f880d01e6 100644
--- a/net/netfilter/nf_synproxy_core.c
+++ b/net/netfilter/nf_synproxy_core.c
@@ -1223,7 +1223,7 @@ nf_synproxy_ipv6_init(struct synproxy_net *snet, struct net *net)
}
snet->hook_ref6++;
- return err;
+ return 0;
}
EXPORT_SYMBOL_GPL(nf_synproxy_ipv6_init);
--
2.20.1
^ permalink raw reply related
* [PATCH net-next v5 1/3] hinic: add rss support
From: Xue Chaojing @ 2019-06-18 6:20 UTC (permalink / raw)
To: davem
Cc: linux-kernel, netdev, luoshaokai, cloud.wangxiaoyun, xuechaojing,
chiqijun, wulike1
In-Reply-To: <20190618062053.7545-1-xuechaojing@huawei.com>
This patch adds rss support for the HINIC driver.
Signed-off-by: Xue Chaojing <xuechaojing@huawei.com>
---
drivers/net/ethernet/huawei/hinic/hinic_dev.h | 26 ++
.../net/ethernet/huawei/hinic/hinic_hw_dev.c | 10 +-
.../net/ethernet/huawei/hinic/hinic_hw_dev.h | 26 ++
.../net/ethernet/huawei/hinic/hinic_hw_wqe.h | 16 ++
.../net/ethernet/huawei/hinic/hinic_main.c | 126 ++++++++-
.../net/ethernet/huawei/hinic/hinic_port.c | 263 ++++++++++++++++++
.../net/ethernet/huawei/hinic/hinic_port.h | 82 ++++++
7 files changed, 541 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_dev.h b/drivers/net/ethernet/huawei/hinic/hinic_dev.h
index 5186cc9023aa..8926768280f2 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_dev.h
+++ b/drivers/net/ethernet/huawei/hinic/hinic_dev.h
@@ -31,6 +31,7 @@
enum hinic_flags {
HINIC_LINK_UP = BIT(0),
HINIC_INTF_UP = BIT(1),
+ HINIC_RSS_ENABLE = BIT(2),
};
struct hinic_rx_mode_work {
@@ -38,6 +39,23 @@ struct hinic_rx_mode_work {
u32 rx_mode;
};
+struct hinic_rss_type {
+ u8 tcp_ipv6_ext;
+ u8 ipv6_ext;
+ u8 tcp_ipv6;
+ u8 ipv6;
+ u8 tcp_ipv4;
+ u8 ipv4;
+ u8 udp_ipv6;
+ u8 udp_ipv4;
+};
+
+enum hinic_rss_hash_type {
+ HINIC_RSS_HASH_ENGINE_TYPE_XOR,
+ HINIC_RSS_HASH_ENGINE_TYPE_TOEP,
+ HINIC_RSS_HASH_ENGINE_TYPE_MAX,
+};
+
struct hinic_dev {
struct net_device *netdev;
struct hinic_hwdev *hwdev;
@@ -45,6 +63,8 @@ struct hinic_dev {
u32 msg_enable;
unsigned int tx_weight;
unsigned int rx_weight;
+ u16 num_qps;
+ u16 max_qps;
unsigned int flags;
@@ -59,6 +79,12 @@ struct hinic_dev {
struct hinic_txq_stats tx_stats;
struct hinic_rxq_stats rx_stats;
+
+ u8 rss_tmpl_idx;
+ u8 rss_hash_engine;
+ u16 num_rss;
+ u16 rss_limit;
+ struct hinic_rss_type rss_type;
};
#endif
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c b/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c
index 756a7e3280bd..5e01672fd47b 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.c
@@ -98,9 +98,6 @@ static int get_capability(struct hinic_hwdev *hwdev,
if (nic_cap->num_qps > HINIC_Q_CTXT_MAX)
nic_cap->num_qps = HINIC_Q_CTXT_MAX;
- /* num_qps must be power of 2 */
- nic_cap->num_qps = BIT(fls(nic_cap->num_qps) - 1);
-
nic_cap->max_qps = dev_cap->max_sqs + 1;
if (nic_cap->max_qps != (dev_cap->max_rqs + 1))
return -EFAULT;
@@ -883,6 +880,13 @@ void hinic_free_hwdev(struct hinic_hwdev *hwdev)
hinic_free_hwif(hwdev->hwif);
}
+int hinic_hwdev_max_num_qps(struct hinic_hwdev *hwdev)
+{
+ struct hinic_cap *nic_cap = &hwdev->nic_cap;
+
+ return nic_cap->max_qps;
+}
+
/**
* hinic_hwdev_num_qps - return the number QPs available for use
* @hwdev: the NIC HW device
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h b/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h
index fba4fe82472a..9c55374077f7 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h
+++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h
@@ -56,6 +56,14 @@ enum hinic_port_cmd {
HINIC_PORT_CMD_SET_PORT_STATE = 41,
+ HINIC_PORT_CMD_SET_RSS_TEMPLATE_TBL = 43,
+
+ HINIC_PORT_CMD_SET_RSS_HASH_ENGINE = 45,
+
+ HINIC_PORT_CMD_RSS_TEMP_MGR = 49,
+
+ HINIC_PORT_CMD_RSS_CFG = 66,
+
HINIC_PORT_CMD_FWCTXT_INIT = 69,
HINIC_PORT_CMD_SET_FUNC_STATE = 93,
@@ -71,6 +79,22 @@ enum hinic_port_cmd {
HINIC_PORT_CMD_SET_LRO_TIMER = 244,
};
+enum hinic_ucode_cmd {
+ HINIC_UCODE_CMD_MODIFY_QUEUE_CONTEXT = 0,
+ HINIC_UCODE_CMD_CLEAN_QUEUE_CONTEXT,
+ HINIC_UCODE_CMD_ARM_SQ,
+ HINIC_UCODE_CMD_ARM_RQ,
+ HINIC_UCODE_CMD_SET_RSS_INDIR_TABLE,
+ HINIC_UCODE_CMD_SET_RSS_CONTEXT_TABLE,
+ HINIC_UCODE_CMD_GET_RSS_INDIR_TABLE,
+ HINIC_UCODE_CMD_GET_RSS_CONTEXT_TABLE,
+ HINIC_UCODE_CMD_SET_IQ_ENABLE,
+ HINIC_UCODE_CMD_SET_RQ_FLUSH = 10
+};
+
+#define NIC_RSS_CMD_TEMP_ALLOC 0x01
+#define NIC_RSS_CMD_TEMP_FREE 0x02
+
enum hinic_mgmt_msg_cmd {
HINIC_MGMT_MSG_CMD_BASE = 160,
@@ -230,6 +254,8 @@ struct hinic_hwdev *hinic_init_hwdev(struct pci_dev *pdev);
void hinic_free_hwdev(struct hinic_hwdev *hwdev);
+int hinic_hwdev_max_num_qps(struct hinic_hwdev *hwdev);
+
int hinic_hwdev_num_qps(struct hinic_hwdev *hwdev);
struct hinic_sq *hinic_hwdev_get_sq(struct hinic_hwdev *hwdev, int i);
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_wqe.h b/drivers/net/ethernet/huawei/hinic/hinic_hw_wqe.h
index ef852b7b57a3..a441b0b89d6f 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_wqe.h
+++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_wqe.h
@@ -239,6 +239,22 @@
#define HINIC_GET_RX_PKT_TYPE(offload_type) \
RQ_CQE_OFFOLAD_TYPE_GET(offload_type, PKT_TYPE)
+#define HINIC_RSS_TYPE_VALID_SHIFT 23
+#define HINIC_RSS_TYPE_TCP_IPV6_EXT_SHIFT 24
+#define HINIC_RSS_TYPE_IPV6_EXT_SHIFT 25
+#define HINIC_RSS_TYPE_TCP_IPV6_SHIFT 26
+#define HINIC_RSS_TYPE_IPV6_SHIFT 27
+#define HINIC_RSS_TYPE_TCP_IPV4_SHIFT 28
+#define HINIC_RSS_TYPE_IPV4_SHIFT 29
+#define HINIC_RSS_TYPE_UDP_IPV6_SHIFT 30
+#define HINIC_RSS_TYPE_UDP_IPV4_SHIFT 31
+
+#define HINIC_RSS_TYPE_SET(val, member) \
+ (((u32)(val) & 0x1) << HINIC_RSS_TYPE_##member##_SHIFT)
+
+#define HINIC_RSS_TYPE_GET(val, member) \
+ (((u32)(val) >> HINIC_RSS_TYPE_##member##_SHIFT) & 0x1)
+
enum hinic_l4offload_type {
HINIC_L4_OFF_DISABLE = 0,
HINIC_TCP_OFFLOAD_ENABLE = 1,
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_main.c b/drivers/net/ethernet/huawei/hinic/hinic_main.c
index 419880564ee5..3020d21ce788 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_main.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_main.c
@@ -391,11 +391,118 @@ static int hinic_configure_max_qnum(struct hinic_dev *nic_dev)
return 0;
}
+static int hinic_rss_init(struct hinic_dev *nic_dev)
+{
+ u32 indir_tbl[HINIC_RSS_INDIR_SIZE] = { 0 };
+ u8 default_rss_key[HINIC_RSS_KEY_SIZE];
+ u8 tmpl_idx = nic_dev->rss_tmpl_idx;
+ int err, i;
+
+ netdev_rss_key_fill(default_rss_key, sizeof(default_rss_key));
+ for (i = 0; i < HINIC_RSS_INDIR_SIZE; i++)
+ indir_tbl[i] = ethtool_rxfh_indir_default(i, nic_dev->num_rss);
+
+ err = hinic_rss_set_template_tbl(nic_dev, tmpl_idx, default_rss_key);
+ if (err)
+ return err;
+
+ err = hinic_rss_set_indir_tbl(nic_dev, tmpl_idx, indir_tbl);
+ if (err)
+ return err;
+
+ err = hinic_set_rss_type(nic_dev, tmpl_idx, nic_dev->rss_type);
+ if (err)
+ return err;
+
+ err = hinic_rss_set_hash_engine(nic_dev, tmpl_idx,
+ nic_dev->rss_hash_engine);
+ if (err)
+ return err;
+
+ err = hinic_rss_cfg(nic_dev, 1, tmpl_idx);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static void hinic_rss_deinit(struct hinic_dev *nic_dev)
+{
+ hinic_rss_cfg(nic_dev, 0, nic_dev->rss_tmpl_idx);
+}
+
+static void hinic_init_rss_parameters(struct hinic_dev *nic_dev)
+{
+ nic_dev->rss_hash_engine = HINIC_RSS_HASH_ENGINE_TYPE_XOR;
+ nic_dev->rss_type.tcp_ipv6_ext = 1;
+ nic_dev->rss_type.ipv6_ext = 1;
+ nic_dev->rss_type.tcp_ipv6 = 1;
+ nic_dev->rss_type.ipv6 = 1;
+ nic_dev->rss_type.tcp_ipv4 = 1;
+ nic_dev->rss_type.ipv4 = 1;
+ nic_dev->rss_type.udp_ipv6 = 1;
+ nic_dev->rss_type.udp_ipv4 = 1;
+}
+
+static void hinic_enable_rss(struct hinic_dev *nic_dev)
+{
+ struct net_device *netdev = nic_dev->netdev;
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+ struct hinic_hwif *hwif = hwdev->hwif;
+ struct pci_dev *pdev = hwif->pdev;
+ int i, node, err = 0;
+ u16 num_cpus = 0;
+
+ nic_dev->max_qps = hinic_hwdev_max_num_qps(hwdev);
+ if (nic_dev->max_qps <= 1) {
+ nic_dev->flags &= ~HINIC_RSS_ENABLE;
+ nic_dev->rss_limit = nic_dev->max_qps;
+ nic_dev->num_qps = nic_dev->max_qps;
+ nic_dev->num_rss = nic_dev->max_qps;
+
+ return;
+ }
+
+ err = hinic_rss_template_alloc(nic_dev, &nic_dev->rss_tmpl_idx);
+ if (err) {
+ netif_err(nic_dev, drv, netdev,
+ "Failed to alloc tmpl_idx for rss, can't enable rss for this function\n");
+ nic_dev->flags &= ~HINIC_RSS_ENABLE;
+ nic_dev->max_qps = 1;
+ nic_dev->rss_limit = nic_dev->max_qps;
+ nic_dev->num_qps = nic_dev->max_qps;
+ nic_dev->num_rss = nic_dev->max_qps;
+
+ return;
+ }
+
+ nic_dev->flags |= HINIC_RSS_ENABLE;
+
+ for (i = 0; i < num_online_cpus(); i++) {
+ node = cpu_to_node(i);
+ if (node == dev_to_node(&pdev->dev))
+ num_cpus++;
+ }
+
+ if (!num_cpus)
+ num_cpus = num_online_cpus();
+
+ nic_dev->num_qps = min_t(u16, nic_dev->max_qps, num_cpus);
+
+ nic_dev->rss_limit = nic_dev->num_qps;
+ nic_dev->num_rss = nic_dev->num_qps;
+
+ hinic_init_rss_parameters(nic_dev);
+ err = hinic_rss_init(nic_dev);
+ if (err)
+ netif_err(nic_dev, drv, netdev, "Failed to init rss\n");
+}
+
static int hinic_open(struct net_device *netdev)
{
struct hinic_dev *nic_dev = netdev_priv(netdev);
enum hinic_port_link_state link_state;
- int err, ret, num_qps;
+ int err, ret;
if (!(nic_dev->flags & HINIC_INTF_UP)) {
err = hinic_hwdev_ifup(nic_dev->hwdev);
@@ -420,6 +527,8 @@ static int hinic_open(struct net_device *netdev)
goto err_create_rxqs;
}
+ hinic_enable_rss(nic_dev);
+
err = hinic_configure_max_qnum(nic_dev);
if (err) {
netif_err(nic_dev, drv, nic_dev->netdev,
@@ -427,9 +536,8 @@ static int hinic_open(struct net_device *netdev)
goto err_port_state;
}
- num_qps = hinic_hwdev_num_qps(nic_dev->hwdev);
- netif_set_real_num_tx_queues(netdev, num_qps);
- netif_set_real_num_rx_queues(netdev, num_qps);
+ netif_set_real_num_tx_queues(netdev, nic_dev->num_qps);
+ netif_set_real_num_rx_queues(netdev, nic_dev->num_qps);
err = hinic_port_set_state(nic_dev, HINIC_PORT_ENABLE);
if (err) {
@@ -485,9 +593,12 @@ static int hinic_open(struct net_device *netdev)
if (ret)
netif_warn(nic_dev, drv, netdev,
"Failed to revert port state\n");
-
err_port_state:
free_rxqs(nic_dev);
+ if (nic_dev->flags & HINIC_RSS_ENABLE) {
+ hinic_rss_deinit(nic_dev);
+ hinic_rss_template_free(nic_dev, nic_dev->rss_tmpl_idx);
+ }
err_create_rxqs:
free_txqs(nic_dev);
@@ -531,6 +642,11 @@ static int hinic_close(struct net_device *netdev)
return err;
}
+ if (nic_dev->flags & HINIC_RSS_ENABLE) {
+ hinic_rss_deinit(nic_dev);
+ hinic_rss_template_free(nic_dev, nic_dev->rss_tmpl_idx);
+ }
+
free_rxqs(nic_dev);
free_txqs(nic_dev);
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_port.c b/drivers/net/ethernet/huawei/hinic/hinic_port.c
index c9aedecd19c9..510cde869ddf 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_port.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_port.c
@@ -553,3 +553,266 @@ int hinic_set_rx_lro_state(struct hinic_dev *nic_dev, u8 lro_en,
return 0;
}
+
+int hinic_rss_set_indir_tbl(struct hinic_dev *nic_dev, u32 tmpl_idx,
+ const u32 *indir_table)
+{
+ struct hinic_rss_indirect_tbl *indir_tbl;
+ struct hinic_func_to_io *func_to_io;
+ struct hinic_cmdq_buf cmd_buf;
+ struct hinic_hwdev *hwdev;
+ struct hinic_hwif *hwif;
+ struct pci_dev *pdev;
+ u32 indir_size;
+ u64 out_param;
+ int err, i;
+ u32 *temp;
+
+ hwdev = nic_dev->hwdev;
+ func_to_io = &hwdev->func_to_io;
+ hwif = hwdev->hwif;
+ pdev = hwif->pdev;
+
+ err = hinic_alloc_cmdq_buf(&func_to_io->cmdqs, &cmd_buf);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to allocate cmdq buf\n");
+ return err;
+ }
+
+ cmd_buf.size = sizeof(*indir_tbl);
+
+ indir_tbl = cmd_buf.buf;
+ indir_tbl->group_index = cpu_to_be32(tmpl_idx);
+
+ for (i = 0; i < HINIC_RSS_INDIR_SIZE; i++) {
+ indir_tbl->entry[i] = indir_table[i];
+
+ if (0x3 == (i & 0x3)) {
+ temp = (u32 *)&indir_tbl->entry[i - 3];
+ *temp = cpu_to_be32(*temp);
+ }
+ }
+
+ /* cfg the rss indirect table by command queue */
+ indir_size = HINIC_RSS_INDIR_SIZE / 2;
+ indir_tbl->offset = 0;
+ indir_tbl->size = cpu_to_be32(indir_size);
+
+ err = hinic_cmdq_direct_resp(&func_to_io->cmdqs, HINIC_MOD_L2NIC,
+ HINIC_UCODE_CMD_SET_RSS_INDIR_TABLE,
+ &cmd_buf, &out_param);
+ if (err || out_param != 0) {
+ dev_err(&pdev->dev, "Failed to set rss indir table\n");
+ err = -EFAULT;
+ goto free_buf;
+ }
+
+ indir_tbl->offset = cpu_to_be32(indir_size);
+ indir_tbl->size = cpu_to_be32(indir_size);
+ memcpy(&indir_tbl->entry[0], &indir_tbl->entry[indir_size], indir_size);
+
+ err = hinic_cmdq_direct_resp(&func_to_io->cmdqs, HINIC_MOD_L2NIC,
+ HINIC_UCODE_CMD_SET_RSS_INDIR_TABLE,
+ &cmd_buf, &out_param);
+ if (err || out_param != 0) {
+ dev_err(&pdev->dev, "Failed to set rss indir table\n");
+ err = -EFAULT;
+ }
+
+free_buf:
+ hinic_free_cmdq_buf(&func_to_io->cmdqs, &cmd_buf);
+
+ return err;
+}
+
+int hinic_set_rss_type(struct hinic_dev *nic_dev, u32 tmpl_idx,
+ struct hinic_rss_type rss_type)
+{
+ struct hinic_rss_context_tbl *ctx_tbl;
+ struct hinic_func_to_io *func_to_io;
+ struct hinic_cmdq_buf cmd_buf;
+ struct hinic_hwdev *hwdev;
+ struct hinic_hwif *hwif;
+ struct pci_dev *pdev;
+ u64 out_param;
+ u32 ctx = 0;
+ int err;
+
+ hwdev = nic_dev->hwdev;
+ func_to_io = &hwdev->func_to_io;
+ hwif = hwdev->hwif;
+ pdev = hwif->pdev;
+
+ err = hinic_alloc_cmdq_buf(&func_to_io->cmdqs, &cmd_buf);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to allocate cmd buf\n");
+ return -ENOMEM;
+ }
+
+ ctx |= HINIC_RSS_TYPE_SET(1, VALID) |
+ HINIC_RSS_TYPE_SET(rss_type.ipv4, IPV4) |
+ HINIC_RSS_TYPE_SET(rss_type.ipv6, IPV6) |
+ HINIC_RSS_TYPE_SET(rss_type.ipv6_ext, IPV6_EXT) |
+ HINIC_RSS_TYPE_SET(rss_type.tcp_ipv4, TCP_IPV4) |
+ HINIC_RSS_TYPE_SET(rss_type.tcp_ipv6, TCP_IPV6) |
+ HINIC_RSS_TYPE_SET(rss_type.tcp_ipv6_ext, TCP_IPV6_EXT) |
+ HINIC_RSS_TYPE_SET(rss_type.udp_ipv4, UDP_IPV4) |
+ HINIC_RSS_TYPE_SET(rss_type.udp_ipv6, UDP_IPV6);
+
+ cmd_buf.size = sizeof(struct hinic_rss_context_tbl);
+
+ ctx_tbl = (struct hinic_rss_context_tbl *)cmd_buf.buf;
+ ctx_tbl->group_index = cpu_to_be32(tmpl_idx);
+ ctx_tbl->offset = 0;
+ ctx_tbl->size = sizeof(u32);
+ ctx_tbl->size = cpu_to_be32(ctx_tbl->size);
+ ctx_tbl->rsvd = 0;
+ ctx_tbl->ctx = cpu_to_be32(ctx);
+
+ /* cfg the rss context table by command queue */
+ err = hinic_cmdq_direct_resp(&func_to_io->cmdqs, HINIC_MOD_L2NIC,
+ HINIC_UCODE_CMD_SET_RSS_CONTEXT_TABLE,
+ &cmd_buf, &out_param);
+
+ hinic_free_cmdq_buf(&func_to_io->cmdqs, &cmd_buf);
+
+ if (err || out_param != 0) {
+ dev_err(&pdev->dev, "Failed to set rss context table, err: %d\n",
+ err);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int hinic_rss_set_template_tbl(struct hinic_dev *nic_dev, u32 template_id,
+ const u8 *temp)
+{
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+ struct hinic_hwif *hwif = hwdev->hwif;
+ struct hinic_rss_key rss_key = { 0 };
+ struct pci_dev *pdev = hwif->pdev;
+ u16 out_size;
+ int err;
+
+ rss_key.func_id = HINIC_HWIF_FUNC_IDX(hwif);
+ rss_key.template_id = template_id;
+ memcpy(rss_key.key, temp, HINIC_RSS_KEY_SIZE);
+
+ err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_SET_RSS_TEMPLATE_TBL,
+ &rss_key, sizeof(rss_key),
+ &rss_key, &out_size);
+ if (err || !out_size || rss_key.status) {
+ dev_err(&pdev->dev,
+ "Failed to set rss hash key, err: %d, status: 0x%x, out size: 0x%x\n",
+ err, rss_key.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int hinic_rss_set_hash_engine(struct hinic_dev *nic_dev, u8 template_id,
+ u8 type)
+{
+ struct hinic_rss_engine_type rss_engine = { 0 };
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+ struct hinic_hwif *hwif = hwdev->hwif;
+ struct pci_dev *pdev = hwif->pdev;
+ u16 out_size;
+ int err;
+
+ rss_engine.func_id = HINIC_HWIF_FUNC_IDX(hwif);
+ rss_engine.hash_engine = type;
+ rss_engine.template_id = template_id;
+
+ err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_SET_RSS_HASH_ENGINE,
+ &rss_engine, sizeof(rss_engine),
+ &rss_engine, &out_size);
+ if (err || !out_size || rss_engine.status) {
+ dev_err(&pdev->dev,
+ "Failed to set hash engine, err: %d, status: 0x%x, out size: 0x%x\n",
+ err, rss_engine.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int hinic_rss_cfg(struct hinic_dev *nic_dev, u8 rss_en, u8 template_id)
+{
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+ struct hinic_rss_config rss_cfg = { 0 };
+ struct hinic_hwif *hwif = hwdev->hwif;
+ struct pci_dev *pdev = hwif->pdev;
+ u16 out_size;
+ int err;
+
+ rss_cfg.func_id = HINIC_HWIF_FUNC_IDX(hwif);
+ rss_cfg.rss_en = rss_en;
+ rss_cfg.template_id = template_id;
+ rss_cfg.rq_priority_number = 0;
+
+ err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_RSS_CFG,
+ &rss_cfg, sizeof(rss_cfg),
+ &rss_cfg, &out_size);
+ if (err || !out_size || rss_cfg.status) {
+ dev_err(&pdev->dev,
+ "Failed to set rss cfg, err: %d, status: 0x%x, out size: 0x%x\n",
+ err, rss_cfg.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int hinic_rss_template_alloc(struct hinic_dev *nic_dev, u8 *tmpl_idx)
+{
+ struct hinic_rss_template_mgmt template_mgmt = { 0 };
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+ struct hinic_hwif *hwif = hwdev->hwif;
+ struct pci_dev *pdev = hwif->pdev;
+ u16 out_size;
+ int err;
+
+ template_mgmt.func_id = HINIC_HWIF_FUNC_IDX(hwif);
+ template_mgmt.cmd = NIC_RSS_CMD_TEMP_ALLOC;
+
+ err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_RSS_TEMP_MGR,
+ &template_mgmt, sizeof(template_mgmt),
+ &template_mgmt, &out_size);
+ if (err || !out_size || template_mgmt.status) {
+ dev_err(&pdev->dev, "Failed to alloc rss template, err: %d, status: 0x%x, out size: 0x%x\n",
+ err, template_mgmt.status, out_size);
+ return -EINVAL;
+ }
+
+ *tmpl_idx = template_mgmt.template_id;
+
+ return 0;
+}
+
+int hinic_rss_template_free(struct hinic_dev *nic_dev, u8 tmpl_idx)
+{
+ struct hinic_rss_template_mgmt template_mgmt = { 0 };
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+ struct hinic_hwif *hwif = hwdev->hwif;
+ struct pci_dev *pdev = hwif->pdev;
+ u16 out_size;
+ int err;
+
+ template_mgmt.func_id = HINIC_HWIF_FUNC_IDX(hwif);
+ template_mgmt.template_id = tmpl_idx;
+ template_mgmt.cmd = NIC_RSS_CMD_TEMP_FREE;
+
+ err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_RSS_TEMP_MGR,
+ &template_mgmt, sizeof(template_mgmt),
+ &template_mgmt, &out_size);
+ if (err || !out_size || template_mgmt.status) {
+ dev_err(&pdev->dev, "Failed to free rss template, err: %d, status: 0x%x, out size: 0x%x\n",
+ err, template_mgmt.status, out_size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_port.h b/drivers/net/ethernet/huawei/hinic/hinic_port.h
index 972b7be460a8..0c9ed17134a7 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_port.h
+++ b/drivers/net/ethernet/huawei/hinic/hinic_port.h
@@ -22,6 +22,9 @@
#include "hinic_dev.h"
+#define HINIC_RSS_KEY_SIZE 40
+#define HINIC_RSS_INDIR_SIZE 256
+
enum hinic_rx_mode {
HINIC_RX_MODE_UC = BIT(0),
HINIC_RX_MODE_MC = BIT(1),
@@ -228,6 +231,67 @@ struct hinic_lro_timer {
u32 timer;
};
+struct hinic_rss_template_mgmt {
+ u8 status;
+ u8 version;
+ u8 rsvd0[6];
+
+ u16 func_id;
+ u8 cmd;
+ u8 template_id;
+ u8 rsvd1[4];
+};
+
+struct hinic_rss_context_tbl {
+ u32 group_index;
+ u32 offset;
+ u32 size;
+ u32 rsvd;
+ u32 ctx;
+};
+
+struct hinic_rss_indirect_tbl {
+ u32 group_index;
+ u32 offset;
+ u32 size;
+ u32 rsvd;
+ u8 entry[HINIC_RSS_INDIR_SIZE];
+};
+
+struct hinic_rss_key {
+ u8 status;
+ u8 version;
+ u8 rsvd0[6];
+
+ u16 func_id;
+ u8 template_id;
+ u8 rsvd1;
+ u8 key[HINIC_RSS_KEY_SIZE];
+};
+
+struct hinic_rss_engine_type {
+ u8 status;
+ u8 version;
+ u8 rsvd0[6];
+
+ u16 func_id;
+ u8 template_id;
+ u8 hash_engine;
+ u8 rsvd1[4];
+};
+
+struct hinic_rss_config {
+ u8 status;
+ u8 version;
+ u8 rsvd0[6];
+
+ u16 func_id;
+ u8 rss_en;
+ u8 template_id;
+ u8 rq_priority_number;
+ u8 rsvd1[11];
+};
+
int hinic_port_add_mac(struct hinic_dev *nic_dev, const u8 *addr,
u16 vlan_id);
@@ -264,4 +328,22 @@ int hinic_set_rx_csum_offload(struct hinic_dev *nic_dev, u32 en);
int hinic_set_rx_lro_state(struct hinic_dev *nic_dev, u8 lro_en,
u32 lro_timer, u32 wqe_num);
+
+int hinic_set_rss_type(struct hinic_dev *nic_dev, u32 tmpl_idx,
+ struct hinic_rss_type rss_type);
+
+int hinic_rss_set_indir_tbl(struct hinic_dev *nic_dev, u32 tmpl_idx,
+ const u32 *indir_table);
+
+int hinic_rss_set_template_tbl(struct hinic_dev *nic_dev, u32 template_id,
+ const u8 *temp);
+
+int hinic_rss_set_hash_engine(struct hinic_dev *nic_dev, u8 template_id,
+ u8 type);
+
+int hinic_rss_cfg(struct hinic_dev *nic_dev, u8 rss_en, u8 template_id);
+
+int hinic_rss_template_alloc(struct hinic_dev *nic_dev, u8 *tmpl_idx);
+
+int hinic_rss_template_free(struct hinic_dev *nic_dev, u8 tmpl_idx);
#endif
--
2.17.1
^ permalink raw reply related
* [PATCH net-next v5 3/3] hinic: add support for rss parameters with ethtool
From: Xue Chaojing @ 2019-06-18 6:20 UTC (permalink / raw)
To: davem
Cc: linux-kernel, netdev, luoshaokai, cloud.wangxiaoyun, xuechaojing,
chiqijun, wulike1
In-Reply-To: <20190618062053.7545-1-xuechaojing@huawei.com>
This patch adds support rss parameters with ethtool,
user can change hash key, hash indirection table, hash
function by ethtool -X, and show rss parameters by ethtool -x.
Signed-off-by: Xue Chaojing <xuechaojing@huawei.com>
---
drivers/net/ethernet/huawei/hinic/hinic_dev.h | 2 +
.../net/ethernet/huawei/hinic/hinic_ethtool.c | 295 ++++++++++++++++++
.../net/ethernet/huawei/hinic/hinic_hw_dev.h | 12 +-
.../net/ethernet/huawei/hinic/hinic_port.c | 126 ++++++++
.../net/ethernet/huawei/hinic/hinic_port.h | 45 +++
5 files changed, 479 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_dev.h b/drivers/net/ethernet/huawei/hinic/hinic_dev.h
index 8926768280f2..5c9bc3319880 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_dev.h
+++ b/drivers/net/ethernet/huawei/hinic/hinic_dev.h
@@ -85,6 +85,8 @@ struct hinic_dev {
u16 num_rss;
u16 rss_limit;
struct hinic_rss_type rss_type;
+ u8 *rss_hkey_user;
+ s32 *rss_indir_user;
};
#endif
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c b/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c
index 2cc97bfef0b8..be28a9a7f033 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c
@@ -149,12 +149,307 @@ static void hinic_get_channels(struct net_device *netdev,
channels->combined_count = 0;
}
+static int hinic_get_rss_hash_opts(struct hinic_dev *nic_dev,
+ struct ethtool_rxnfc *cmd)
+{
+ struct hinic_rss_type rss_type = { 0 };
+ int err;
+
+ cmd->data = 0;
+
+ if (!(nic_dev->flags & HINIC_RSS_ENABLE))
+ return 0;
+
+ err = hinic_get_rss_type(nic_dev, nic_dev->rss_tmpl_idx,
+ &rss_type);
+ if (err)
+ return err;
+
+ cmd->data = RXH_IP_SRC | RXH_IP_DST;
+ switch (cmd->flow_type) {
+ case TCP_V4_FLOW:
+ if (rss_type.tcp_ipv4)
+ cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+ break;
+ case TCP_V6_FLOW:
+ if (rss_type.tcp_ipv6)
+ cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+ break;
+ case UDP_V4_FLOW:
+ if (rss_type.udp_ipv4)
+ cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+ break;
+ case UDP_V6_FLOW:
+ if (rss_type.udp_ipv6)
+ cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+ break;
+ case IPV4_FLOW:
+ case IPV6_FLOW:
+ break;
+ default:
+ cmd->data = 0;
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int set_l4_rss_hash_ops(struct ethtool_rxnfc *cmd,
+ struct hinic_rss_type *rss_type)
+{
+ u8 rss_l4_en = 0;
+
+ switch (cmd->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
+ case 0:
+ rss_l4_en = 0;
+ break;
+ case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
+ rss_l4_en = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (cmd->flow_type) {
+ case TCP_V4_FLOW:
+ rss_type->tcp_ipv4 = rss_l4_en;
+ break;
+ case TCP_V6_FLOW:
+ rss_type->tcp_ipv6 = rss_l4_en;
+ break;
+ case UDP_V4_FLOW:
+ rss_type->udp_ipv4 = rss_l4_en;
+ break;
+ case UDP_V6_FLOW:
+ rss_type->udp_ipv6 = rss_l4_en;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int hinic_set_rss_hash_opts(struct hinic_dev *nic_dev,
+ struct ethtool_rxnfc *cmd)
+{
+ struct hinic_rss_type *rss_type = &nic_dev->rss_type;
+ int err;
+
+ if (!(nic_dev->flags & HINIC_RSS_ENABLE)) {
+ cmd->data = 0;
+ return -EOPNOTSUPP;
+ }
+
+ /* RSS does not support anything other than hashing
+ * to queues on src and dst IPs and ports
+ */
+ if (cmd->data & ~(RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 |
+ RXH_L4_B_2_3))
+ return -EINVAL;
+
+ /* We need at least the IP SRC and DEST fields for hashing */
+ if (!(cmd->data & RXH_IP_SRC) || !(cmd->data & RXH_IP_DST))
+ return -EINVAL;
+
+ err = hinic_get_rss_type(nic_dev,
+ nic_dev->rss_tmpl_idx, rss_type);
+ if (err)
+ return -EFAULT;
+
+ switch (cmd->flow_type) {
+ case TCP_V4_FLOW:
+ case TCP_V6_FLOW:
+ case UDP_V4_FLOW:
+ case UDP_V6_FLOW:
+ err = set_l4_rss_hash_ops(cmd, rss_type);
+ if (err)
+ return err;
+ break;
+ case IPV4_FLOW:
+ rss_type->ipv4 = 1;
+ break;
+ case IPV6_FLOW:
+ rss_type->ipv6 = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ err = hinic_set_rss_type(nic_dev, nic_dev->rss_tmpl_idx,
+ *rss_type);
+ if (err)
+ return -EFAULT;
+
+ return 0;
+}
+
+static int __set_rss_rxfh(struct net_device *netdev,
+ const u32 *indir, const u8 *key)
+{
+ struct hinic_dev *nic_dev = netdev_priv(netdev);
+ int err;
+
+ if (indir) {
+ if (!nic_dev->rss_indir_user) {
+ nic_dev->rss_indir_user =
+ kzalloc(sizeof(u32) * HINIC_RSS_INDIR_SIZE,
+ GFP_KERNEL);
+ if (!nic_dev->rss_indir_user)
+ return -ENOMEM;
+ }
+
+ memcpy(nic_dev->rss_indir_user, indir,
+ sizeof(u32) * HINIC_RSS_INDIR_SIZE);
+
+ err = hinic_rss_set_indir_tbl(nic_dev,
+ nic_dev->rss_tmpl_idx, indir);
+ if (err)
+ return -EFAULT;
+ }
+
+ if (key) {
+ if (!nic_dev->rss_hkey_user) {
+ nic_dev->rss_hkey_user =
+ kzalloc(HINIC_RSS_KEY_SIZE * 2, GFP_KERNEL);
+
+ if (!nic_dev->rss_hkey_user)
+ return -ENOMEM;
+ }
+
+ memcpy(nic_dev->rss_hkey_user, key, HINIC_RSS_KEY_SIZE);
+
+ err = hinic_rss_set_template_tbl(nic_dev,
+ nic_dev->rss_tmpl_idx, key);
+ if (err)
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int hinic_get_rxnfc(struct net_device *netdev,
+ struct ethtool_rxnfc *cmd, u32 *rule_locs)
+{
+ struct hinic_dev *nic_dev = netdev_priv(netdev);
+ int err = 0;
+
+ switch (cmd->cmd) {
+ case ETHTOOL_GRXRINGS:
+ cmd->data = nic_dev->num_qps;
+ break;
+ case ETHTOOL_GRXFH:
+ err = hinic_get_rss_hash_opts(nic_dev, cmd);
+ break;
+ default:
+ err = -EOPNOTSUPP;
+ break;
+ }
+
+ return err;
+}
+
+static int hinic_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
+{
+ struct hinic_dev *nic_dev = netdev_priv(netdev);
+ int err = 0;
+
+ switch (cmd->cmd) {
+ case ETHTOOL_SRXFH:
+ err = hinic_set_rss_hash_opts(nic_dev, cmd);
+ break;
+ default:
+ err = -EOPNOTSUPP;
+ break;
+ }
+
+ return err;
+}
+
+static int hinic_get_rxfh(struct net_device *netdev,
+ u32 *indir, u8 *key, u8 *hfunc)
+{
+ struct hinic_dev *nic_dev = netdev_priv(netdev);
+ u8 hash_engine_type = 0;
+ int err = 0;
+
+ if (!(nic_dev->flags & HINIC_RSS_ENABLE))
+ return -EOPNOTSUPP;
+
+ if (hfunc) {
+ err = hinic_rss_get_hash_engine(nic_dev,
+ nic_dev->rss_tmpl_idx,
+ &hash_engine_type);
+ if (err)
+ return -EFAULT;
+
+ *hfunc = hash_engine_type ? ETH_RSS_HASH_TOP : ETH_RSS_HASH_XOR;
+ }
+
+ if (indir) {
+ err = hinic_rss_get_indir_tbl(nic_dev,
+ nic_dev->rss_tmpl_idx, indir);
+ if (err)
+ return -EFAULT;
+ }
+
+ if (key)
+ err = hinic_rss_get_template_tbl(nic_dev,
+ nic_dev->rss_tmpl_idx, key);
+
+ return err;
+}
+
+static int hinic_set_rxfh(struct net_device *netdev, const u32 *indir,
+ const u8 *key, const u8 hfunc)
+{
+ struct hinic_dev *nic_dev = netdev_priv(netdev);
+ int err = 0;
+
+ if (!(nic_dev->flags & HINIC_RSS_ENABLE))
+ return -EOPNOTSUPP;
+
+ if (hfunc != ETH_RSS_HASH_NO_CHANGE) {
+ if (hfunc != ETH_RSS_HASH_TOP && hfunc != ETH_RSS_HASH_XOR)
+ return -EOPNOTSUPP;
+
+ nic_dev->rss_hash_engine = (hfunc == ETH_RSS_HASH_XOR) ?
+ HINIC_RSS_HASH_ENGINE_TYPE_XOR :
+ HINIC_RSS_HASH_ENGINE_TYPE_TOEP;
+ err = hinic_rss_set_hash_engine
+ (nic_dev, nic_dev->rss_tmpl_idx,
+ nic_dev->rss_hash_engine);
+ if (err)
+ return -EFAULT;
+ }
+
+ err = __set_rss_rxfh(netdev, indir, key);
+
+ return err;
+}
+
+static u32 hinic_get_rxfh_key_size(struct net_device *netdev)
+{
+ return HINIC_RSS_KEY_SIZE;
+}
+
+static u32 hinic_get_rxfh_indir_size(struct net_device *netdev)
+{
+ return HINIC_RSS_INDIR_SIZE;
+}
+
static const struct ethtool_ops hinic_ethtool_ops = {
.get_link_ksettings = hinic_get_link_ksettings,
.get_drvinfo = hinic_get_drvinfo,
.get_link = ethtool_op_get_link,
.get_ringparam = hinic_get_ringparam,
.get_channels = hinic_get_channels,
+ .get_rxnfc = hinic_get_rxnfc,
+ .set_rxnfc = hinic_set_rxnfc,
+ .get_rxfh_key_size = hinic_get_rxfh_key_size,
+ .get_rxfh_indir_size = hinic_get_rxfh_indir_size,
+ .get_rxfh = hinic_get_rxfh,
+ .set_rxfh = hinic_set_rxfh,
};
void hinic_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h b/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h
index 9c55374077f7..7f854392f4e7 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h
+++ b/drivers/net/ethernet/huawei/hinic/hinic_hw_dev.h
@@ -54,11 +54,21 @@ enum hinic_port_cmd {
HINIC_PORT_CMD_SET_RX_CSUM = 26,
+ HINIC_PORT_CMD_GET_RSS_TEMPLATE_INDIR_TBL = 37,
+
HINIC_PORT_CMD_SET_PORT_STATE = 41,
HINIC_PORT_CMD_SET_RSS_TEMPLATE_TBL = 43,
- HINIC_PORT_CMD_SET_RSS_HASH_ENGINE = 45,
+ HINIC_PORT_CMD_GET_RSS_TEMPLATE_TBL = 44,
+
+ HINIC_PORT_CMD_SET_RSS_HASH_ENGINE = 45,
+
+ HINIC_PORT_CMD_GET_RSS_HASH_ENGINE = 46,
+
+ HINIC_PORT_CMD_GET_RSS_CTX_TBL = 47,
+
+ HINIC_PORT_CMD_SET_RSS_CTX_TBL = 48,
HINIC_PORT_CMD_RSS_TEMP_MGR = 49,
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_port.c b/drivers/net/ethernet/huawei/hinic/hinic_port.c
index 510cde869ddf..3bd24cb8ed4b 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_port.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_port.c
@@ -625,6 +625,36 @@ int hinic_rss_set_indir_tbl(struct hinic_dev *nic_dev, u32 tmpl_idx,
return err;
}
+int hinic_rss_get_indir_tbl(struct hinic_dev *nic_dev, u32 tmpl_idx,
+ u32 *indir_table)
+{
+ struct hinic_rss_indir_table rss_cfg = { 0 };
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+ struct hinic_hwif *hwif = hwdev->hwif;
+ struct pci_dev *pdev = hwif->pdev;
+ u16 out_size = sizeof(rss_cfg);
+ int err = 0, i;
+
+ rss_cfg.func_id = HINIC_HWIF_FUNC_IDX(hwif);
+ rss_cfg.template_id = tmpl_idx;
+
+ err = hinic_port_msg_cmd(hwdev,
+ HINIC_PORT_CMD_GET_RSS_TEMPLATE_INDIR_TBL,
+ &rss_cfg, sizeof(rss_cfg), &rss_cfg,
+ &out_size);
+ if (err || !out_size || rss_cfg.status) {
+ dev_err(&pdev->dev, "Failed to get indir table, err: %d, status: 0x%x, out size: 0x%x\n",
+ err, rss_cfg.status, out_size);
+ return -EINVAL;
+ }
+
+ hinic_be32_to_cpu(rss_cfg.indir, HINIC_RSS_INDIR_SIZE);
+ for (i = 0; i < HINIC_RSS_INDIR_SIZE; i++)
+ indir_table[i] = rss_cfg.indir[i];
+
+ return 0;
+}
+
int hinic_set_rss_type(struct hinic_dev *nic_dev, u32 tmpl_idx,
struct hinic_rss_type rss_type)
{
@@ -685,6 +715,44 @@ int hinic_set_rss_type(struct hinic_dev *nic_dev, u32 tmpl_idx,
return 0;
}
+int hinic_get_rss_type(struct hinic_dev *nic_dev, u32 tmpl_idx,
+ struct hinic_rss_type *rss_type)
+{
+ struct hinic_rss_context_table ctx_tbl = { 0 };
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+ struct hinic_hwif *hwif = hwdev->hwif;
+ struct pci_dev *pdev = hwif->pdev;
+ u16 out_size = sizeof(ctx_tbl);
+ int err;
+
+ if (!hwdev || !rss_type)
+ return -EINVAL;
+
+ ctx_tbl.func_id = HINIC_HWIF_FUNC_IDX(hwif);
+ ctx_tbl.template_id = tmpl_idx;
+
+ err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_GET_RSS_CTX_TBL,
+ &ctx_tbl, sizeof(ctx_tbl),
+ &ctx_tbl, &out_size);
+ if (err || !out_size || ctx_tbl.status) {
+ dev_err(&pdev->dev, "Failed to get hash type, err: %d, status: 0x%x, out size: 0x%x\n",
+ err, ctx_tbl.status, out_size);
+ return -EINVAL;
+ }
+
+ rss_type->ipv4 = HINIC_RSS_TYPE_GET(ctx_tbl.context, IPV4);
+ rss_type->ipv6 = HINIC_RSS_TYPE_GET(ctx_tbl.context, IPV6);
+ rss_type->ipv6_ext = HINIC_RSS_TYPE_GET(ctx_tbl.context, IPV6_EXT);
+ rss_type->tcp_ipv4 = HINIC_RSS_TYPE_GET(ctx_tbl.context, TCP_IPV4);
+ rss_type->tcp_ipv6 = HINIC_RSS_TYPE_GET(ctx_tbl.context, TCP_IPV6);
+ rss_type->tcp_ipv6_ext = HINIC_RSS_TYPE_GET(ctx_tbl.context,
+ TCP_IPV6_EXT);
+ rss_type->udp_ipv4 = HINIC_RSS_TYPE_GET(ctx_tbl.context, UDP_IPV4);
+ rss_type->udp_ipv6 = HINIC_RSS_TYPE_GET(ctx_tbl.context, UDP_IPV6);
+
+ return 0;
+}
+
int hinic_rss_set_template_tbl(struct hinic_dev *nic_dev, u32 template_id,
const u8 *temp)
{
@@ -712,6 +780,36 @@ int hinic_rss_set_template_tbl(struct hinic_dev *nic_dev, u32 template_id,
return 0;
}
+int hinic_rss_get_template_tbl(struct hinic_dev *nic_dev, u32 tmpl_idx,
+ u8 *temp)
+{
+ struct hinic_rss_template_key temp_key = { 0 };
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+ struct hinic_hwif *hwif = hwdev->hwif;
+ struct pci_dev *pdev = hwif->pdev;
+ u16 out_size = sizeof(temp_key);
+ int err;
+
+ if (!hwdev || !temp)
+ return -EINVAL;
+
+ temp_key.func_id = HINIC_HWIF_FUNC_IDX(hwif);
+ temp_key.template_id = tmpl_idx;
+
+ err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_GET_RSS_TEMPLATE_TBL,
+ &temp_key, sizeof(temp_key),
+ &temp_key, &out_size);
+ if (err || !out_size || temp_key.status) {
+ dev_err(&pdev->dev, "Failed to set hash key, err: %d, status: 0x%x, out size: 0x%x\n",
+ err, temp_key.status, out_size);
+ return -EINVAL;
+ }
+
+ memcpy(temp, temp_key.key, HINIC_RSS_KEY_SIZE);
+
+ return 0;
+}
+
int hinic_rss_set_hash_engine(struct hinic_dev *nic_dev, u8 template_id,
u8 type)
{
@@ -739,6 +837,34 @@ int hinic_rss_set_hash_engine(struct hinic_dev *nic_dev, u8 template_id,
return 0;
}
+int hinic_rss_get_hash_engine(struct hinic_dev *nic_dev, u8 tmpl_idx, u8 *type)
+{
+ struct hinic_rss_engine_type hash_type = { 0 };
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+ struct hinic_hwif *hwif = hwdev->hwif;
+ struct pci_dev *pdev = hwif->pdev;
+ u16 out_size = sizeof(hash_type);
+ int err;
+
+ if (!hwdev || !type)
+ return -EINVAL;
+
+ hash_type.func_id = HINIC_HWIF_FUNC_IDX(hwif);
+ hash_type.template_id = tmpl_idx;
+
+ err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_GET_RSS_HASH_ENGINE,
+ &hash_type, sizeof(hash_type),
+ &hash_type, &out_size);
+ if (err || !out_size || hash_type.status) {
+ dev_err(&pdev->dev, "Failed to get hash engine, err: %d, status: 0x%x, out size: 0x%x\n",
+ err, hash_type.status, out_size);
+ return -EINVAL;
+ }
+
+ *type = hash_type.hash_engine;
+ return 0;
+}
+
int hinic_rss_cfg(struct hinic_dev *nic_dev, u8 rss_en, u8 template_id)
{
struct hinic_hwdev *hwdev = nic_dev->hwdev;
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_port.h b/drivers/net/ethernet/huawei/hinic/hinic_port.h
index dafa3ca18af4..f177945d64ae 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_port.h
+++ b/drivers/net/ethernet/huawei/hinic/hinic_port.h
@@ -242,6 +242,17 @@ struct hinic_rss_template_mgmt {
u8 rsvd1[4];
};
+struct hinic_rss_template_key {
+ u8 status;
+ u8 version;
+ u8 rsvd0[6];
+
+ u16 func_id;
+ u8 template_id;
+ u8 rsvd1;
+ u8 key[HINIC_RSS_KEY_SIZE];
+};
+
struct hinic_rss_context_tbl {
u32 group_index;
u32 offset;
@@ -250,6 +261,17 @@ struct hinic_rss_context_tbl {
u32 ctx;
};
+struct hinic_rss_context_table {
+ u8 status;
+ u8 version;
+ u8 rsvd0[6];
+
+ u16 func_id;
+ u8 template_id;
+ u8 rsvd1;
+ u32 context;
+};
+
struct hinic_rss_indirect_tbl {
u32 group_index;
u32 offset;
@@ -258,6 +280,17 @@ struct hinic_rss_indirect_tbl {
u8 entry[HINIC_RSS_INDIR_SIZE];
};
+struct hinic_rss_indir_table {
+ u8 status;
+ u8 version;
+ u8 rsvd0[6];
+
+ u16 func_id;
+ u8 template_id;
+ u8 rsvd1;
+ u8 indir[HINIC_RSS_INDIR_SIZE];
+};
+
struct hinic_rss_key {
u8 status;
u8 version;
@@ -348,4 +381,16 @@ int hinic_rss_template_alloc(struct hinic_dev *nic_dev, u8 *tmpl_idx);
int hinic_rss_template_free(struct hinic_dev *nic_dev, u8 tmpl_idx);
void hinic_set_ethtool_ops(struct net_device *netdev);
+
+int hinic_get_rss_type(struct hinic_dev *nic_dev, u32 tmpl_idx,
+ struct hinic_rss_type *rss_type);
+
+int hinic_rss_get_indir_tbl(struct hinic_dev *nic_dev, u32 tmpl_idx,
+ u32 *indir_table);
+
+int hinic_rss_get_template_tbl(struct hinic_dev *nic_dev, u32 tmpl_idx,
+ u8 *temp);
+
+int hinic_rss_get_hash_engine(struct hinic_dev *nic_dev, u8 tmpl_idx,
+ u8 *type);
#endif
--
2.17.1
^ permalink raw reply related
* [PATCH net-next v5 0/3] hinic: add rss support and rss parameters configuration
From: Xue Chaojing @ 2019-06-18 6:20 UTC (permalink / raw)
To: davem
Cc: linux-kernel, netdev, luoshaokai, cloud.wangxiaoyun, xuechaojing,
chiqijun, wulike1
This series add rss support for HINIC driver and implement the ethtool
interface related to rss parameter configuration. user can use ethtool
configure rss parameters or show rss parameters.
Xue Chaojing (3):
hinic: add rss support
hinic: move ethtool code into hinic_ethtool
hinic: add support for rss parameters with ethtool
drivers/net/ethernet/huawei/hinic/Makefile | 2 +-
drivers/net/ethernet/huawei/hinic/hinic_dev.h | 28 ++
.../net/ethernet/huawei/hinic/hinic_ethtool.c | 458 ++++++++++++++++++
.../net/ethernet/huawei/hinic/hinic_hw_dev.c | 10 +-
.../net/ethernet/huawei/hinic/hinic_hw_dev.h | 36 ++
.../net/ethernet/huawei/hinic/hinic_hw_wqe.h | 16 +
.../net/ethernet/huawei/hinic/hinic_main.c | 260 +++++-----
.../net/ethernet/huawei/hinic/hinic_port.c | 389 +++++++++++++++
.../net/ethernet/huawei/hinic/hinic_port.h | 129 +++++
9 files changed, 1186 insertions(+), 142 deletions(-)
create mode 100644 drivers/net/ethernet/huawei/hinic/hinic_ethtool.c
--
2.17.1
^ permalink raw reply
* [PATCH net-next v5 2/3] hinic: move ethtool code into hinic_ethtool
From: Xue Chaojing @ 2019-06-18 6:20 UTC (permalink / raw)
To: davem
Cc: linux-kernel, netdev, luoshaokai, cloud.wangxiaoyun, xuechaojing,
chiqijun, wulike1
In-Reply-To: <20190618062053.7545-1-xuechaojing@huawei.com>
This patch moves ethtool code from hinic_main.c to hinic_ethtool.c
Signed-off-by: Xue Chaojing <xuechaojing@huawei.com>
---
drivers/net/ethernet/huawei/hinic/Makefile | 2 +-
.../net/ethernet/huawei/hinic/hinic_ethtool.c | 163 ++++++++++++++++++
.../net/ethernet/huawei/hinic/hinic_main.c | 134 +-------------
.../net/ethernet/huawei/hinic/hinic_port.h | 2 +
4 files changed, 167 insertions(+), 134 deletions(-)
create mode 100644 drivers/net/ethernet/huawei/hinic/hinic_ethtool.c
diff --git a/drivers/net/ethernet/huawei/hinic/Makefile b/drivers/net/ethernet/huawei/hinic/Makefile
index 289ce88bb2d0..c592f1a0f54b 100644
--- a/drivers/net/ethernet/huawei/hinic/Makefile
+++ b/drivers/net/ethernet/huawei/hinic/Makefile
@@ -3,4 +3,4 @@ obj-$(CONFIG_HINIC) += hinic.o
hinic-y := hinic_main.o hinic_tx.o hinic_rx.o hinic_port.o hinic_hw_dev.o \
hinic_hw_io.o hinic_hw_qp.o hinic_hw_cmdq.o hinic_hw_wq.o \
hinic_hw_mgmt.o hinic_hw_api_cmd.o hinic_hw_eqs.o hinic_hw_if.o \
- hinic_common.o
+ hinic_common.o hinic_ethtool.o
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c b/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c
new file mode 100644
index 000000000000..2cc97bfef0b8
--- /dev/null
+++ b/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Huawei HiNIC PCI Express Linux driver
+ * Copyright(c) 2017 Huawei Technologies Co., Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/etherdevice.h>
+#include <linux/netdevice.h>
+#include <linux/if_vlan.h>
+#include <linux/ethtool.h>
+#include <linux/vmalloc.h>
+
+#include "hinic_hw_qp.h"
+#include "hinic_hw_dev.h"
+#include "hinic_port.h"
+#include "hinic_tx.h"
+#include "hinic_rx.h"
+#include "hinic_dev.h"
+
+static void set_link_speed(struct ethtool_link_ksettings *link_ksettings,
+ enum hinic_speed speed)
+{
+ switch (speed) {
+ case HINIC_SPEED_10MB_LINK:
+ link_ksettings->base.speed = SPEED_10;
+ break;
+
+ case HINIC_SPEED_100MB_LINK:
+ link_ksettings->base.speed = SPEED_100;
+ break;
+
+ case HINIC_SPEED_1000MB_LINK:
+ link_ksettings->base.speed = SPEED_1000;
+ break;
+
+ case HINIC_SPEED_10GB_LINK:
+ link_ksettings->base.speed = SPEED_10000;
+ break;
+
+ case HINIC_SPEED_25GB_LINK:
+ link_ksettings->base.speed = SPEED_25000;
+ break;
+
+ case HINIC_SPEED_40GB_LINK:
+ link_ksettings->base.speed = SPEED_40000;
+ break;
+
+ case HINIC_SPEED_100GB_LINK:
+ link_ksettings->base.speed = SPEED_100000;
+ break;
+
+ default:
+ link_ksettings->base.speed = SPEED_UNKNOWN;
+ break;
+ }
+}
+
+static int hinic_get_link_ksettings(struct net_device *netdev,
+ struct ethtool_link_ksettings
+ *link_ksettings)
+{
+ struct hinic_dev *nic_dev = netdev_priv(netdev);
+ enum hinic_port_link_state link_state;
+ struct hinic_port_cap port_cap;
+ int err;
+
+ ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising);
+ ethtool_link_ksettings_add_link_mode(link_ksettings, supported,
+ Autoneg);
+
+ link_ksettings->base.speed = SPEED_UNKNOWN;
+ link_ksettings->base.autoneg = AUTONEG_DISABLE;
+ link_ksettings->base.duplex = DUPLEX_UNKNOWN;
+
+ err = hinic_port_get_cap(nic_dev, &port_cap);
+ if (err)
+ return err;
+
+ err = hinic_port_link_state(nic_dev, &link_state);
+ if (err)
+ return err;
+
+ if (link_state != HINIC_LINK_STATE_UP)
+ return err;
+
+ set_link_speed(link_ksettings, port_cap.speed);
+
+ if (!!(port_cap.autoneg_cap & HINIC_AUTONEG_SUPPORTED))
+ ethtool_link_ksettings_add_link_mode(link_ksettings,
+ advertising, Autoneg);
+
+ if (port_cap.autoneg_state == HINIC_AUTONEG_ACTIVE)
+ link_ksettings->base.autoneg = AUTONEG_ENABLE;
+
+ link_ksettings->base.duplex = (port_cap.duplex == HINIC_DUPLEX_FULL) ?
+ DUPLEX_FULL : DUPLEX_HALF;
+ return 0;
+}
+
+static void hinic_get_drvinfo(struct net_device *netdev,
+ struct ethtool_drvinfo *info)
+{
+ struct hinic_dev *nic_dev = netdev_priv(netdev);
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+ struct hinic_hwif *hwif = hwdev->hwif;
+
+ strlcpy(info->driver, HINIC_DRV_NAME, sizeof(info->driver));
+ strlcpy(info->bus_info, pci_name(hwif->pdev), sizeof(info->bus_info));
+}
+
+static void hinic_get_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring)
+{
+ ring->rx_max_pending = HINIC_RQ_DEPTH;
+ ring->tx_max_pending = HINIC_SQ_DEPTH;
+ ring->rx_pending = HINIC_RQ_DEPTH;
+ ring->tx_pending = HINIC_SQ_DEPTH;
+}
+
+static void hinic_get_channels(struct net_device *netdev,
+ struct ethtool_channels *channels)
+{
+ struct hinic_dev *nic_dev = netdev_priv(netdev);
+ struct hinic_hwdev *hwdev = nic_dev->hwdev;
+
+ channels->max_rx = hwdev->nic_cap.max_qps;
+ channels->max_tx = hwdev->nic_cap.max_qps;
+ channels->max_other = 0;
+ channels->max_combined = 0;
+ channels->rx_count = hinic_hwdev_num_qps(hwdev);
+ channels->tx_count = hinic_hwdev_num_qps(hwdev);
+ channels->other_count = 0;
+ channels->combined_count = 0;
+}
+
+static const struct ethtool_ops hinic_ethtool_ops = {
+ .get_link_ksettings = hinic_get_link_ksettings,
+ .get_drvinfo = hinic_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ .get_ringparam = hinic_get_ringparam,
+ .get_channels = hinic_get_channels,
+};
+
+void hinic_set_ethtool_ops(struct net_device *netdev)
+{
+ netdev->ethtool_ops = &hinic_ethtool_ops;
+}
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_main.c b/drivers/net/ethernet/huawei/hinic/hinic_main.c
index 3020d21ce788..853fc3e7b514 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_main.c
+++ b/drivers/net/ethernet/huawei/hinic/hinic_main.c
@@ -80,138 +80,6 @@ static int set_features(struct hinic_dev *nic_dev,
netdev_features_t pre_features,
netdev_features_t features, bool force_change);
-static void set_link_speed(struct ethtool_link_ksettings *link_ksettings,
- enum hinic_speed speed)
-{
- switch (speed) {
- case HINIC_SPEED_10MB_LINK:
- link_ksettings->base.speed = SPEED_10;
- break;
-
- case HINIC_SPEED_100MB_LINK:
- link_ksettings->base.speed = SPEED_100;
- break;
-
- case HINIC_SPEED_1000MB_LINK:
- link_ksettings->base.speed = SPEED_1000;
- break;
-
- case HINIC_SPEED_10GB_LINK:
- link_ksettings->base.speed = SPEED_10000;
- break;
-
- case HINIC_SPEED_25GB_LINK:
- link_ksettings->base.speed = SPEED_25000;
- break;
-
- case HINIC_SPEED_40GB_LINK:
- link_ksettings->base.speed = SPEED_40000;
- break;
-
- case HINIC_SPEED_100GB_LINK:
- link_ksettings->base.speed = SPEED_100000;
- break;
-
- default:
- link_ksettings->base.speed = SPEED_UNKNOWN;
- break;
- }
-}
-
-static int hinic_get_link_ksettings(struct net_device *netdev,
- struct ethtool_link_ksettings
- *link_ksettings)
-{
- struct hinic_dev *nic_dev = netdev_priv(netdev);
- enum hinic_port_link_state link_state;
- struct hinic_port_cap port_cap;
- int err;
-
- ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising);
- ethtool_link_ksettings_add_link_mode(link_ksettings, supported,
- Autoneg);
-
- link_ksettings->base.speed = SPEED_UNKNOWN;
- link_ksettings->base.autoneg = AUTONEG_DISABLE;
- link_ksettings->base.duplex = DUPLEX_UNKNOWN;
-
- err = hinic_port_get_cap(nic_dev, &port_cap);
- if (err) {
- netif_err(nic_dev, drv, netdev,
- "Failed to get port capabilities\n");
- return err;
- }
-
- err = hinic_port_link_state(nic_dev, &link_state);
- if (err) {
- netif_err(nic_dev, drv, netdev,
- "Failed to get port link state\n");
- return err;
- }
-
- if (link_state != HINIC_LINK_STATE_UP) {
- netif_info(nic_dev, drv, netdev, "No link\n");
- return err;
- }
-
- set_link_speed(link_ksettings, port_cap.speed);
-
- if (!!(port_cap.autoneg_cap & HINIC_AUTONEG_SUPPORTED))
- ethtool_link_ksettings_add_link_mode(link_ksettings,
- advertising, Autoneg);
-
- if (port_cap.autoneg_state == HINIC_AUTONEG_ACTIVE)
- link_ksettings->base.autoneg = AUTONEG_ENABLE;
-
- link_ksettings->base.duplex = (port_cap.duplex == HINIC_DUPLEX_FULL) ?
- DUPLEX_FULL : DUPLEX_HALF;
- return 0;
-}
-
-static void hinic_get_drvinfo(struct net_device *netdev,
- struct ethtool_drvinfo *info)
-{
- struct hinic_dev *nic_dev = netdev_priv(netdev);
- struct hinic_hwdev *hwdev = nic_dev->hwdev;
- struct hinic_hwif *hwif = hwdev->hwif;
-
- strlcpy(info->driver, HINIC_DRV_NAME, sizeof(info->driver));
- strlcpy(info->bus_info, pci_name(hwif->pdev), sizeof(info->bus_info));
-}
-
-static void hinic_get_ringparam(struct net_device *netdev,
- struct ethtool_ringparam *ring)
-{
- ring->rx_max_pending = HINIC_RQ_DEPTH;
- ring->tx_max_pending = HINIC_SQ_DEPTH;
- ring->rx_pending = HINIC_RQ_DEPTH;
- ring->tx_pending = HINIC_SQ_DEPTH;
-}
-
-static void hinic_get_channels(struct net_device *netdev,
- struct ethtool_channels *channels)
-{
- struct hinic_dev *nic_dev = netdev_priv(netdev);
- struct hinic_hwdev *hwdev = nic_dev->hwdev;
-
- channels->max_rx = hwdev->nic_cap.max_qps;
- channels->max_tx = hwdev->nic_cap.max_qps;
- channels->max_other = 0;
- channels->max_combined = 0;
- channels->rx_count = hinic_hwdev_num_qps(hwdev);
- channels->tx_count = hinic_hwdev_num_qps(hwdev);
- channels->other_count = 0;
- channels->combined_count = 0;
-}
-
-static const struct ethtool_ops hinic_ethtool_ops = {
- .get_link_ksettings = hinic_get_link_ksettings,
- .get_drvinfo = hinic_get_drvinfo,
- .get_link = ethtool_op_get_link,
- .get_ringparam = hinic_get_ringparam,
- .get_channels = hinic_get_channels,
-};
-
static void update_rx_stats(struct hinic_dev *nic_dev, struct hinic_rxq *rxq)
{
struct hinic_rxq_stats *nic_rx_stats = &nic_dev->rx_stats;
@@ -1092,8 +960,8 @@ static int nic_dev_init(struct pci_dev *pdev)
goto err_alloc_etherdev;
}
+ hinic_set_ethtool_ops(netdev);
netdev->netdev_ops = &hinic_netdev_ops;
- netdev->ethtool_ops = &hinic_ethtool_ops;
netdev->max_mtu = ETH_MAX_MTU;
nic_dev = netdev_priv(netdev);
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_port.h b/drivers/net/ethernet/huawei/hinic/hinic_port.h
index 0c9ed17134a7..dafa3ca18af4 100644
--- a/drivers/net/ethernet/huawei/hinic/hinic_port.h
+++ b/drivers/net/ethernet/huawei/hinic/hinic_port.h
@@ -346,4 +346,6 @@ int hinic_rss_cfg(struct hinic_dev *nic_dev, u8 rss_en, u8 template_id);
int hinic_rss_template_alloc(struct hinic_dev *nic_dev, u8 *tmpl_idx);
int hinic_rss_template_free(struct hinic_dev *nic_dev, u8 tmpl_idx);
+
+void hinic_set_ethtool_ops(struct net_device *netdev);
#endif
--
2.17.1
^ permalink raw reply related
* Re: [PATCH v3 bpf-next 0/9] bpf: bounded loops and other features
From: Paul Chaignon @ 2019-06-18 14:05 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: Xiao Han, David S. Miller, Daniel Borkmann, Networking, bpf,
Kernel Team, Andrii Nakryiko, Alexei Starovoitov
In-Reply-To: <70187096-9876-b004-0ccb-8293618f384f@fb.com>
On Mon, Jun 17, 2019 at 06:57PM, Alexei Starovoitov wrote:
> On 6/17/19 9:39 AM, Andrii Nakryiko wrote:
> > On Sat, Jun 15, 2019 at 12:12 PM Alexei Starovoitov <ast@kernel.org> wrote:
> >>
> >> v2->v3: fixed issues in backtracking pointed out by Andrii.
> >> The next step is to add a lot more tests for backtracking.
> >>
> >
> > Tests would be great, verifier complexity is at the level, where it's
> > very easy to miss issues.
> >
> > Was fuzzying approach ever discussed for BPF verifier? I.e., have a
> > fuzzer to generate both legal and illegal random small programs. Then
> > re-implement verifier as user-level program with straightforward
> > recursive exhaustive verification (so no state pruning logic, no
> > precise/coarse, etc, just register/stack state tracking) of all
> > possible branches. If kernel verifier's verdict differs from
> > user-level verifier's verdict - flag that as a test case and figure
> > out why they differ. Obviously that would work well only for small
> > programs, but that should be a good first step already.
> >
> > In addition, if this is done, that user-land verifier can be a HUGE
> > help to BPF application developers, as libbpf would (potentially) be
> > able to generate better error messages using it as well.
>
> In theory that sounds good, but doesn't work in practice.
> The kernel verifier keeps changing faster than user space can catch up.
> It's also relying on loaded maps and all sorts of callbacks that
> check context, allowed helpers, maps, combinations of them from all
> over the kernel.
> The last effort to build kernel verifier as-is into .o and link
> with kmalloc/map wrappers in user space was here:
> https://github.com/iovisor/bpf-fuzzer
> It was fuzzing the verifier and was able to find few minor bugs.
> But it quickly bit rotted.
We've been working (with Xiao Han, cc'ed) on an update of bpf-fuzzer. It
helped us find a few issues in the verifier (mostly thanks to
warn_on("verifier bug")s). I'll probably send a patchset to the main
repository in the next few weeks.
Updating the glue code (userspace wrappers) is okay so far, as long as
done regularly.
[...]
>
> I think syzbot is still generating bpf programs. iirc it found
> one bug in the past in the verifier core.
syzkaller's template description of BPF programs is very limited. It
produces valid BPF instructions, but loaded programs make little sense,
are trivial or invalid, and don't go very far in the verifier. We
probably can't rely on syzkaller to be effective for the verifier.
> I think the only way to make verifier more robust is to keep
> adding new test cases manually.
> Most interesting bugs we found by humans.
Tests and reviews are definitely the most effective ways to find bugs,
despite the above two fuzzers. The verifier is complex enough that the
random approach of fuzzers has a hard time covering the code.
Paul
^ permalink raw reply
* Re: [PATCH v2 00/17] net: introduce Qualcomm IPA driver
From: Alex Elder @ 2019-06-18 14:00 UTC (permalink / raw)
To: Johannes Berg, Arnd Bergmann
Cc: abhishek.esse, Ben Chan, Bjorn Andersson, cpratapa, David Miller,
Dan Williams, DTML, Eric Caruso, evgreen, Ilias Apalodimas,
Linux ARM, linux-arm-msm, Linux Kernel Mailing List, linux-soc,
Networking, Subash Abhinov Kasiviswanathan, syadagir
In-Reply-To: <583907409fad854bd3c18be688ec2724ad7a60e9.camel@sipsolutions.net>
On 6/17/19 7:14 AM, Johannes Berg wrote:
> On Tue, 2019-06-11 at 13:56 +0200, Arnd Bergmann wrote:
>
> [...]
>
> Looking at the flags again,
I sort of talked about this in my message a little earlier, but I
now see I was partially mistaken. I thought these flags were
used in messages but they're real device ("port") configuration
flags.
>> #define RMNET_FLAGS_INGRESS_DEAGGREGATION (1U << 0)
>
> This one I'm not sure I understand - seems weird to have such a
> fundamental thing as a *configuration* on the channel.
Let me use the term "connection" to refer to the single pathway
that carries data between the AP and modem. And "channel" to
refer to one of several multiplexed data streams carried over
that connection. (If there's better terminology, please say
so; I just want to be clear in what I'm talking about.)
Deaggregation is a connection property, not a channel property.
And it looks like that's exactly how it's used in the rmnet
driver. The hardware is capable of aggregating QMAP packets
arriving on a connection into a single buffer, so this provides
a way of requesting it do that.
>> #define RMNET_FLAGS_INGRESS_MAP_COMMANDS (1U << 1)
>
> Similar here? If you have flow control you probably want to use it?
I agree with that, though perhaps there are cases where it
is pointless, or can't be supported, so one might want to
simply *not* implement/advertise the feature. I don't know.
>> #define RMNET_FLAGS_INGRESS_MAP_CKSUMV4 (1U << 2)
>
> This again looks like a hardware specific feature (ipv4 checksum)? Not
> sure why this is set by userspace.
>
>> #define RMNET_FLAGS_EGRESS_MAP_CKSUMV4 (1U << 3)
>
> This could be set with ethtool instead, I suppose.
As I said in my earlier message, I think I concur about this.
I think the IPA driver could easily hide the checksum offload
capability, and if it can truly be controlled as needed
using existing methods there's no need to encumber the
WWAN framework with it.
-Alex
> johannes
>
^ permalink raw reply
* Re: [PATCH net-next v1 3/5] net: stmmac: drop the reset GPIO from struct stmmac_mdio_bus_data
From: Linus Walleij @ 2019-06-18 14:00 UTC (permalink / raw)
To: Martin Blumenstingl
Cc: netdev, Giuseppe CAVALLARO, Alexandre TORGUE, Jose Abreu,
David S. Miller, Andrew Lunn, Linux ARM,
linux-kernel@vger.kernel.org
In-Reply-To: <20190615100932.27101-4-martin.blumenstingl@googlemail.com>
On Sat, Jun 15, 2019 at 12:09 PM Martin Blumenstingl
<martin.blumenstingl@googlemail.com> wrote:
> No platform uses the "reset_gpio" field from stmmac_mdio_bus_data
> anymore. Drop it so we don't get any new consumers either.
>
> Plain GPIO numbers are being deprecated in favor of GPIO descriptors. If
> needed any new non-OF platform can add a GPIO descriptor lookup table.
> devm_gpiod_get_optional() will find the GPIO in that case.
>
> Suggested-by: Linus Walleij <linus.walleij@linaro.org>
> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Yours,
Linus Walleij
^ permalink raw reply
* Re: [PATCH 1/2] net: intel: igb: minor ethool regdump amendment
From: Andrew Lunn @ 2019-06-18 13:58 UTC (permalink / raw)
To: Artem Bityutskiy
Cc: David S. Miller, Jeff Kirsher, intel-wired-lan, netdev,
Todd Fujinaka
In-Reply-To: <20190618115513.99661-1-dedekind1@gmail.com>
On Tue, Jun 18, 2019 at 02:55:12PM +0300, Artem Bityutskiy wrote:
> From: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Hi Artem.
The subject line is missing a t in ethtool.
> Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Otherwise
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply
* re: netfilter: nft_ct: add ct expectations support
From: Colin Ian King @ 2019-06-18 13:57 UTC (permalink / raw)
To: Stéphane Veyret, Pablo Neira Ayuso, Jozsef Kadlecsik,
Florian Westphal, David S. Miller, netfilter-devel, coreteam,
netdev
Cc: linux-kernel@vger.kernel.org
Hi,
Static analysis with Coverity on linux-next has found a potential issue
with the following commit:
commit 857b46027d6f91150797295752581b7155b9d0e1
Author: Stéphane Veyret <sveyret@gmail.com>
Date: Sat May 25 15:30:58 2019 +0200
netfilter: nft_ct: add ct expectations support
Specifically in function nft_ct_expect_obj_eval)() in the following code:
+ help = nfct_help(ct);
+ if (!help)
+ help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
+
+ if (help->expecting[NF_CT_EXPECT_CLASS_DEFAULT] >= priv->size) {
+ regs->verdict.code = NFT_BREAK;
+ return;
+ }
The call to nf_ct_helper_ext_add can potentially return NULL, however,
this is not being checked and pointer 'help' is being dereferenced even
though it potentially can be null.
Colin
^ permalink raw reply
* Re: general protection fault in sctp_sched_prio_sched
From: Marcelo Ricardo Leitner @ 2019-06-18 13:54 UTC (permalink / raw)
To: Hillf Danton
Cc: syzbot, davem@davemloft.net, linux-kernel@vger.kernel.org,
linux-sctp@vger.kernel.org, lucien.xin@gmail.com,
netdev@vger.kernel.org, nhorman@tuxdriver.com,
syzkaller-bugs@googlegroups.com, vyasevich@gmail.com
In-Reply-To: <20190618080401.11768-1-hdanton@sina.com>
Hi,
On Tue, Jun 18, 2019 at 04:04:01PM +0800, Hillf Danton wrote:
>
> Hello Marcelo
>
> On Mon, 17 Jun 2019 22:43:38 +0800 Marcelo Ricardo Leitner wrote:
> > On Mon, Jun 17, 2019 at 10:49:13AM -0300, Marcelo Ricardo Leitner wrote:
> > > Hi,
> > >
> > > On Sun, Jun 16, 2019 at 11:38:03PM +0800, Hillf Danton wrote:
> > > >
> > > > Hello Syzbot
> > > >
> > > > On Sat, 15 Jun 2019 16:36:06 -0700 (PDT) syzbot wrote:
> > > > > Hello,
> > > > >
> > > > > syzbot found the following crash on:
> > > > >
> > > ...
> > > > Check prio_head and bail out if it is not valid.
> > > >
> > > > Thanks
> > > > Hillf
> > > > ----->8---
> > > > ---
> > > > net/sctp/stream_sched_prio.c | 2 ++
> > > > 1 file changed, 2 insertions(+)
> > > >
> > > > diff --git a/net/sctp/stream_sched_prio.c b/net/sctp/stream_sched_prio.c
> > > > index 2245083..db25a43 100644
> > > > --- a/net/sctp/stream_sched_prio.c
> > > > +++ b/net/sctp/stream_sched_prio.c
> > > > @@ -135,6 +135,8 @@ static void sctp_sched_prio_sched(struct sctp_stream *stream,
> > > > struct sctp_stream_priorities *prio, *prio_head;
> > > >
> > > > prio_head = soute->prio_head;
> > > > + if (!prio_head)
> > > > + return;
> > > >
> > > > /* Nothing to do if already scheduled */
> > > > if (!list_empty(&soute->prio_list))
> > > > --
> > >
> > > Thanks but this is not a good fix for this. It will cause the stream
> > > to never be scheduled.
> > >
> Thanks very much for the light you are casting.
>
> > > The problem happens because of the fault injection that happened a bit
> > > before the crash, in here:
> > >
> > > int sctp_stream_init_ext(struct sctp_stream *stream, __u16 sid)
> > > {
> > > struct sctp_stream_out_ext *soute;
> > >
> > > soute = kzalloc(sizeof(*soute), GFP_KERNEL);
> > > if (!soute)
> > > return -ENOMEM;
> > > SCTP_SO(stream, sid)->ext = soute; <---- [A]
> > >
> > > return sctp_sched_init_sid(stream, sid, GFP_KERNEL);
> > > ^^^^^^^^^^^^---- [B] failed
> > > }
> > >
> Eagle eye.
>
> > > This causes the 1st sendmsg to bail out with the error. When the 2nd
> > > one gets in, it will:
> > >
> > > sctp_sendmsg_to_asoc()
> > > {
> > > ...
> > > if (unlikely(!SCTP_SO(&asoc->stream, sinfo->sinfo_stream)->ext)) {
> > > ^^^^^--- [C]
> > > err = sctp_stream_init_ext(&asoc->stream, sinfo->sinfo_stream);
> > > if (err)
> > > goto err;
> > > }
> > >
> > > [A] leaves ext initialized, despite the failed in [B]. Then in [C], it
> > > will not try to initialize again.
> > >
> Fairly concise.
>
> > > We need to either uninitialize ->ext as error handling for [B], or
> > > improve the check on [C].
> >
> > The former one, please. This should be enough (untested):
> >
> > diff --git a/net/sctp/stream.c b/net/sctp/stream.c
> > index 93ed07877337..25946604af85 100644
> > --- a/net/sctp/stream.c
> > +++ b/net/sctp/stream.c
> > @@ -153,13 +153,20 @@ int sctp_stream_init(struct sctp_stream *stream, __u1=
> > 6 outcnt, __u16 incnt,
> > int sctp_stream_init_ext(struct sctp_stream *stream, __u16 sid)
> > {
> > struct sctp_stream_out_ext *soute;
> > + int ret;
> >
> > soute = kzalloc(sizeof(*soute), GFP_KERNEL);
> > if (!soute)
> > return -ENOMEM;
> > SCTP_SO(stream, sid)->ext = soute;
> >
> > - return sctp_sched_init_sid(stream, sid, GFP_KERNEL);
> > + ret = sctp_sched_init_sid(stream, sid, GFP_KERNEL);
> > + if (ret) {
> > + kfree(SCTP_SO(stream, sid)->ext);
> > + SCTP_SO(stream, sid)->ext = NULL;
[D]
> > + }
> > +
> > + return ret;
> > }
> >
> Definitely nice.
>
> > void sctp_stream_free(struct sctp_stream *stream)
> >
> Hmmm, ->ext will be valid, provided it is loaded with a valid slab in
> sctp_stream_init_ext() regardless of whether sid is successfully
> initialised, until it is released, for instance, in sctp_stream_free(),
> and based on that assumption, it looks hardly likely that ->ext has a
> chance to create a gfp in sctp_sched_prio_sched().
I'm not sure I follow you. Anyway, with the patch above, after calling
sctp_stream_init_ext() ->ext will be either completely valid, or it
will not be present at all as it is seting ->ext to NULL if sid
initialization ended up failing.
Marcelo
^ permalink raw reply
* Re: [RFC bpf-next 0/7] Programming socket lookup with BPF
From: Florian Westphal @ 2019-06-18 13:52 UTC (permalink / raw)
To: Jakub Sitnicki; +Cc: netdev, bpf, kernel-team
In-Reply-To: <20190618130050.8344-1-jakub@cloudflare.com>
Jakub Sitnicki <jakub@cloudflare.com> wrote:
> - XDP programs using bpf_sk_lookup helpers, like load balancers, can't
> find the listening socket to check for SYN cookies with TPROXY redirect.
Sorry for the question, but where is the problem?
(i.e., is it with TPROXY or bpf side)?
> - TPROXY takes a reference to the listening socket on dispatch, which
> raises lock contention concerns.
FWIW this could be avoided in similar way as to how we handle noref dsts.
The only reason we need to take the reference at the moment is because
once skb leaves the TPROXY target hook, the skb could leave rcu
protection as well at some point (nfqueue for example).
Maybe its even enough to move reference taking to nfqueue and add
'noref' destructor, that would allow skb_steal_sock to propagate
refcounted value in __inet_lookup_skb.
So, at least for this part I don't see a technical reason why this
has to grab a reference for listener socket.
> - Traffic steering configuration is split over several iptables rules, at
> least one per service, which makes configuration changes error prone.
Could you perhaps sketch an example ruleset (doesn't have to be complete
nor parse-able by itpables-restore), I would just like to understand if
there is any room for improvement on netfilter/iptables/nft side.
Thanks,
Florian
^ permalink raw reply
* Re: [PATCH net-next v1 08/11] xdp: tracking page_pool resources and safe removal
From: Ivan Khoronzhuk @ 2019-06-18 13:48 UTC (permalink / raw)
To: Ilias Apalodimas
Cc: Tariq Toukan, Jesper Dangaard Brouer, netdev@vger.kernel.org,
Toke Høiland-Jørgensen, toshiaki.makita1@gmail.com,
grygorii.strashko@ti.com, mcroce@redhat.com
In-Reply-To: <20190618133012.GA2055@apalos>
On Tue, Jun 18, 2019 at 04:30:12PM +0300, Ilias Apalodimas wrote:
>Hi Ivan, Tariq,
>
>> >>>+
>[...]
>> >>
>> >>What would you recommend to do for the following situation:
>> >>
>> >>Same receive queue is shared between 2 network devices. The receive ring is
>> >>filled by pages from page_pool, but you don't know the actual port (ndev)
>> >>filling this ring, because a device is recognized only after packet is
>> >>received.
>> >>
>> >>The API is so that xdp rxq is bind to network device, each frame has
>> >>reference
>> >>on it, so rxq ndev must be static. That means each netdev has it's own rxq
>> >>instance even no need in it. Thus, after your changes, page must be
>> >>returned to
>> >>the pool it was taken from, or released from old pool and recycled in
>> >>new one
>> >>somehow.
>> >>
>> >>And that is inconvenience at least. It's hard to move pages between
>> >>pools w/o
>> >>performance penalty. No way to use common pool either, as unreg_rxq now
>> >>drops
>> >>the pool and 2 rxqa can't reference same pool.
>> >>
>> >
>> >Within the single netdev, separate page_pool instances are anyway
>> >created for different RX rings, working under different NAPI's.
>>
>> The circumstances are so that same RX ring is shared between 2
>> netdevs... and netdev can be known only after descriptor/packet is
>> received. Thus, while filling RX ring, there is no actual device,
>> but when packet is received it has to be recycled to appropriate
>> net device pool. Before this change there were no difference from
>> which pool the page was allocated to fill RX ring, as there were no
>> owner. After this change there is owner - netdev page pool.
>>
>> For cpsw the dma unmap is common for both netdevs and no difference
>> who is freeing the page, but there is difference which pool it's
>> freed to.
>Since 2 netdevs are sharing one queue you'll need locking right?
>(Assuming that the rx-irq per device can end up on a different core)
No, rx-irq is not per device, same queue is shared only for descs,
farther it's separate queue with separate pool. Even rx-irq is per
device, no issues, as I said, it has it's own page pool, every queue
and every ndev, no need in locking, for pools...
>We discussed that ideally page pools should be alocated per hardware queue.
This is about one hw queue shared between ndevs. Page pool is separate
for each hw queues and each ndevs ofc.
>If you indeed need locking (and pay the performance penalty anyway) i wonder if
>there's anything preventing you from keeping the same principle, i.e allocate a
>pool per queue
page pool is per queue.
>pool per queue and handle the recycling to the proper ndev internally.
>That way only the first device will be responsible of
>allocating/recycling/maintaining the pool state.
No. There is more dependencies then it looks like, see rxq_info ...
The final recycling is ended not internally.
--
Regards,
Ivan Khoronzhuk
^ 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