Netdev List
 help / color / mirror / Atom feed
* [net-next:master 597/618] drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c:444:23: sparse: symbol 'mvpp2_cls_flow_get' was not declared. Should it be static?
From: kbuild test robot @ 2018-07-14  1:27 UTC (permalink / raw)
  To: Maxime Chevallier; +Cc: kbuild-all, netdev, Antoine Tenart, linux-kernel

tree:   https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git master
head:   c921c2077b32081617789a645120148bc8b60c98
commit: f9358e12a0af53d107df09d4c0254425b6a10468 [597/618] net: mvpp2: split ingress traffic into multiple flows
reproduce:
        # apt-get install sparse
        git checkout f9358e12a0af53d107df09d4c0254425b6a10468
        make ARCH=x86_64 allmodconfig
        make C=1 CF=-D__CHECK_ENDIAN__


sparse warnings: (new ones prefixed by >>)

>> drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c:444:23: sparse: symbol 'mvpp2_cls_flow_get' was not declared. Should it be static?

Please review and possibly fold the followup patch.

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

^ permalink raw reply

* Re: [PATCH] net: ethtool: fix spelling mistake: "tubale" -> "tunable"
From: David Miller @ 2018-07-14  1:26 UTC (permalink / raw)
  To: mhei; +Cc: netdev, linux-kernel
In-Reply-To: <20180711211055.14318-1-mhei@heimpold.de>

From: Michael Heimpold <mhei@heimpold.de>
Date: Wed, 11 Jul 2018 23:10:55 +0200

> Signed-off-by: Michael Heimpold <mhei@heimpold.de>

Applied, thanks.

^ permalink raw reply

* Re: [PATCH] of: mdio: Support fixed links in of_phy_get_and_connect()
From: David Miller @ 2018-07-14  1:25 UTC (permalink / raw)
  To: linus.walleij; +Cc: andrew, f.fainelli, netdev, Laurent.pinchart
In-Reply-To: <20180711174511.15308-1-linus.walleij@linaro.org>

From: Linus Walleij <linus.walleij@linaro.org>
Date: Wed, 11 Jul 2018 19:45:11 +0200

> By a simple extension of of_phy_get_and_connect() drivers
> that have a fixed link on e.g. RGMII can support also
> fixed links, so in addition to:
> 
> ethernet-port {
> 	phy-mode = "rgmii";
> 	phy-handle = <&foo>;
> };
> 
> This setup with a fixed-link node and no phy-handle will
> now also work just fine:
> 
> ethernet-port {
> 	phy-mode = "rgmii";
> 	fixed-link {
> 		speed = <1000>;
> 		full-duplex;
> 		pause;
> 	};
> };
> 
> This is very helpful for connecting random ethernet ports
> to e.g. DSA switches that typically reside on fixed links.
> 
> The phy-mode is still there as the fixes link in this case
> is still an RGMII link.
> 
> Tested on the Cortina Gemini driver with the Vitesse DSA
> router chip on a fixed 1Gbit link.
> 
> Suggested-by: Andrew Lunn <andrew@lunn.ch>
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

Applied.

^ permalink raw reply

* Re: [PATCH net-next] net: sched: refactor flower walk to iterate over idr
From: David Miller @ 2018-07-14  1:24 UTC (permalink / raw)
  To: vladbu; +Cc: netdev, jhs, xiyou.wangcong, jiri
In-Reply-To: <1531132151-2321-1-git-send-email-vladbu@mellanox.com>

From: Vlad Buslov <vladbu@mellanox.com>
Date: Mon,  9 Jul 2018 13:29:11 +0300

> Extend struct tcf_walker with additional 'cookie' field. It is intended to
> be used by classifier walk implementations to continue iteration directly
> from particular filter, instead of iterating 'skip' number of times.
> 
> Change flower walk implementation to save filter handle in 'cookie'. Each
> time flower walk is called, it looks up filter with saved handle directly
> with idr, instead of iterating over filter linked list 'skip' number of
> times. This change improves complexity of dumping flower classifier from
> quadratic to linearithmic. (assuming idr lookup has logarithmic complexity)
> 
> Reviewed-by: Jiri Pirko <jiri@mellanox.com>
> Signed-off-by: Vlad Buslov <vladbu@mellanox.com>

Applied, thank you.

^ permalink raw reply

* Re: [bpf-next,v3,11/13] tools: bpf: make use of reallocarray
From: Jakub Kicinski @ 2018-07-14  1:16 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: alexei.starovoitov, daniel, Andrey Ignatov, oss-drivers, netdev
In-Reply-To: <46440aba-be3f-a3d2-9f39-b7c2446ba50b@roeck-us.net>

On Fri, 13 Jul 2018 17:31:34 -0700, Guenter Roeck wrote:
> On 07/13/2018 05:07 PM, Jakub Kicinski wrote:
> > On Fri, 13 Jul 2018 16:53:05 -0700, Guenter Roeck wrote:  
> >> Hi,
> >>
> >> On Tue, Jul 10, 2018 at 02:43:05PM -0700, Jakub Kicinski wrote:  
> >>> reallocarray() is a safer variant of realloc which checks for
> >>> multiplication overflow in case of array allocation.  Since it's
> >>> not available in Glibc < 2.26 import kernel's overflow.h and
> >>> add a static inline implementation when needed.  Use feature
> >>> detection to probe for existence of reallocarray.
> >>>      
> >>
> >> This probe doesn't work on my system (Ubuntu 16.04).
> >>
> >> libbpf.c: In function ‘bpf_object__add_program’:
> >> libbpf.c:326:10: error: implicit declaration of function ‘reallocarray’  
> > 
> > No way :( :(  Maybe you have to clean the build directory hard?
> > Maybe you have old feature check results or some such?
> >   
> 
> Unlikely. This is seen by my test builders which always start from a clean state.
> 
> $ lsb_release -a
> No LSB modules are available.
> Distributor ID:	Ubuntu
> Description:	Ubuntu 16.04.4 LTS
> Release:	16.04
> Codename:	xenial
> $ gcc --version
> gcc (Ubuntu 5.4.0-6ubuntu1~16.04.10) 5.4.0 20160609
> Copyright (C) 2015 Free Software Foundation, Inc.
> This is free software; see the source for copying conditions.  There is NO
> warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
> $ ld --version
> GNU ld (GNU Binutils for Ubuntu) 2.26.1
> Copyright (C) 2015 Free Software Foundation, Inc.
> This program is free software; you may redistribute it under the terms of
> the GNU General Public License version 3 or (at your option) a later version.
> This program has absolutely no warranty.
> $ git describe
> next-20180713
> $ git clean -d -x -f -q
> $ make allmodconfig
> $ make tools/perf
> ...
> libbpf.c: In function ‘bpf_object__add_program’:
> libbpf.c:326:10: error: implicit declaration of function ‘reallocarray’

Oh, you're not building perf!  Looks like I missed adding reallocarray
to the default feature set on which perf depends, and since given that
features get reused (libbpf won't get to run its own feature detection)
we have to test for reallocarray there:

diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
index 5b6dda3b1ca8..f216b2f5c3d7 100644
--- a/tools/build/Makefile.feature
+++ b/tools/build/Makefile.feature
@@ -57,6 +57,7 @@ FEATURE_TESTS_BASIC :=                  \
         libunwind-aarch64               \
         pthread-attr-setaffinity-np     \
         pthread-barrier                \
+        reallocarray                    \
         stackprotector-all              \
         timerfd                         \
         libdw-dwarf-unwind              \

^ permalink raw reply related

* [RFC PATCH net-next] net: mvpp2: mvpp2_cls_flow_get() can be static
From: kbuild test robot @ 2018-07-14  1:27 UTC (permalink / raw)
  To: Maxime Chevallier; +Cc: kbuild-all, netdev, Antoine Tenart, linux-kernel
In-Reply-To: <201807140954.503e2wSM%fengguang.wu@intel.com>


Fixes: f9358e12a0af ("net: mvpp2: split ingress traffic into multiple flows")
Signed-off-by: kbuild test robot <fengguang.wu@intel.com>
---
 mvpp2_cls.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c
index dc7dfa9..723d0ba 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c
@@ -557,7 +557,7 @@ static int mvpp2_flow_set_hek_fields(struct mvpp2_cls_flow_entry *fe,
 	return 0;
 }
 
-struct mvpp2_cls_flow *mvpp2_cls_flow_get(int flow)
+static struct mvpp2_cls_flow *mvpp2_cls_flow_get(int flow)
 {
 	if (flow >= MVPP2_N_FLOWS)
 		return NULL;

^ permalink raw reply related

* Re: [PATCH net-next v2 5/7] net: mvneta: Allocate page for the descriptor
From: David Miller @ 2018-07-14  1:23 UTC (permalink / raw)
  To: gregory.clement
  Cc: andrew, jason, antoine.tenart, netdev, linux-kernel,
	maxime.chevallier, nadavh, yelena, thomas.petazzoni,
	miquel.raynal, mw, dima, linux-arm-kernel, sebastian.hesselbarth
In-Reply-To: <20180713161841.11202-6-gregory.clement@bootlin.com>

From: Gregory CLEMENT <gregory.clement@bootlin.com>
Date: Fri, 13 Jul 2018 18:18:39 +0200

> -static int mvneta_rx_refill(struct mvneta_port *pp,
> -			    struct mvneta_rx_desc *rx_desc,
> -			    struct mvneta_rx_queue *rxq)
> -
> +/* Allocate page per descriptor */
> +static inline int mvneta_rx_refill(struct mvneta_port *pp,
> +				   struct mvneta_rx_desc *rx_desc,

Please do not use inline functions in foo.c files, let the compiler
decide.

Thank you.

^ permalink raw reply

* Re: [bpf-next,v3,11/13] tools: bpf: make use of reallocarray
From: Guenter Roeck @ 2018-07-14  0:31 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: alexei.starovoitov, daniel, Andrey Ignatov, oss-drivers, netdev
In-Reply-To: <20180713170758.66b01079@cakuba.lan>

On 07/13/2018 05:07 PM, Jakub Kicinski wrote:
> On Fri, 13 Jul 2018 16:53:05 -0700, Guenter Roeck wrote:
>> Hi,
>>
>> On Tue, Jul 10, 2018 at 02:43:05PM -0700, Jakub Kicinski wrote:
>>> reallocarray() is a safer variant of realloc which checks for
>>> multiplication overflow in case of array allocation.  Since it's
>>> not available in Glibc < 2.26 import kernel's overflow.h and
>>> add a static inline implementation when needed.  Use feature
>>> detection to probe for existence of reallocarray.
>>>    
>>
>> This probe doesn't work on my system (Ubuntu 16.04).
>>
>> libbpf.c: In function ‘bpf_object__add_program’:
>> libbpf.c:326:10: error: implicit declaration of function ‘reallocarray’
> 
> No way :( :(  Maybe you have to clean the build directory hard?
> Maybe you have old feature check results or some such?
> 

Unlikely. This is seen by my test builders which always start from a clean state.

$ lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 16.04.4 LTS
Release:	16.04
Codename:	xenial
$ gcc --version
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.10) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ ld --version
GNU ld (GNU Binutils for Ubuntu) 2.26.1
Copyright (C) 2015 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or (at your option) a later version.
This program has absolutely no warranty.
$ git describe
next-20180713
$ git clean -d -x -f -q
$ make allmodconfig
$ make tools/perf
...
libbpf.c: In function ‘bpf_object__add_program’:
libbpf.c:326:10: error: implicit declaration of function ‘reallocarray’

Guenter

^ permalink raw reply

* Re: [PATCH net-next v6 01/11] net: sched: use rcu for action cookie update
From: Cong Wang @ 2018-07-14  0:14 UTC (permalink / raw)
  To: David Miller
  Cc: Vlad Buslov, Linux Kernel Network Developers, Jamal Hadi Salim,
	Jiri Pirko, Alexei Starovoitov, Daniel Borkmann,
	Yevgeny Kliteynik, Jiri Pirko
In-Reply-To: <20180713.151110.334103662560259751.davem@davemloft.net>

On Fri, Jul 13, 2018 at 3:11 PM David Miller <davem@davemloft.net> wrote:
>
> From: Cong Wang <xiyou.wangcong@gmail.com>
> Date: Fri, 13 Jul 2018 14:51:15 -0700
>
> > Can we at least agree you have no justification for this change in
> > this changelog?
>
> He stated that he wishes to make this subsystem more lockless, and he
> cannot do that without making the action cookie handling use RCU.

This isn't enough given RCU writers are recommended (subject
to exceptions) to have locks. Let's move this discussion on patch
00/11 where I provided more details. :)


>
> I agree with the stated goal, and the necessity of this kind of change.
>
> Therefore I applied the patch.
>
> I really don't see what the problem is.
>
> I also gave a couple days for this patch set to get reviewed.  If you
> have a problem, please respond to the patch posting.  When I see nobody
> is reviewing, that is when I step in and make my own judgment.
>
> So when you want your objection to be heard, please do so in a timely
> manner.  That helps all of us.

I 100% understand given how much workload you have. I am not even
saying to revert or something.

My only complain is the goal of lockless is very hard or nearly
impossible to achieve, unless there is some secret hiding from me.
And I am trying to get it exposed in my response to 00/11, by offering
an opportunity to prove I am wrong! :)

The problem with this patch, 01/11, is trivial comparing to the
discussion in 00/11, that is crucial for whether the whole patchset(s)
makes sense.

Thanks for taking care of it anyway!

^ permalink raw reply

* Re: [bpf-next,v3,11/13] tools: bpf: make use of reallocarray
From: Jakub Kicinski @ 2018-07-14  0:07 UTC (permalink / raw)
  To: Guenter Roeck
  Cc: alexei.starovoitov, daniel, Andrey Ignatov, oss-drivers, netdev
In-Reply-To: <20180713235305.GA2779@roeck-us.net>

On Fri, 13 Jul 2018 16:53:05 -0700, Guenter Roeck wrote:
> Hi,
> 
> On Tue, Jul 10, 2018 at 02:43:05PM -0700, Jakub Kicinski wrote:
> > reallocarray() is a safer variant of realloc which checks for
> > multiplication overflow in case of array allocation.  Since it's
> > not available in Glibc < 2.26 import kernel's overflow.h and
> > add a static inline implementation when needed.  Use feature
> > detection to probe for existence of reallocarray.
> >   
> 
> This probe doesn't work on my system (Ubuntu 16.04).
> 
> libbpf.c: In function ‘bpf_object__add_program’:
> libbpf.c:326:10: error: implicit declaration of function ‘reallocarray’

No way :( :(  Maybe you have to clean the build directory hard?  
Maybe you have old feature check results or some such?

# lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 16.04.2 LTS
Release:	16.04
Codename:	xenial
# rm -rf /tmp/bpftool
# mkdir /tmp/bpftool
# make -C tools/bpf/bpftool/ O=/tmp/bpftool
make: Entering directory '/tmp/linux/tools/bpf/bpftool'

Auto-detecting system features:
...                        libbfd: [ OFF ]
...        disassembler-four-args: [ OFF ]

  CC       /tmp/bpftool/map_perf_ring.o
  CC       /tmp/bpftool/xlated_dumper.o
  CC       /tmp/bpftool/perf.o
  CC       /tmp/bpftool/prog.o
  CC       /tmp/bpftool/common.o
  CC       /tmp/bpftool/cgroup.o
  CC       /tmp/bpftool/main.o
  CC       /tmp/bpftool/json_writer.o
  CC       /tmp/bpftool/cfg.o
  CC       /tmp/bpftool/map.o
  CC       /tmp/bpftool/jit_disasm.o
  CC       /tmp/bpftool/disasm.o
make[1]: Entering directory '/tmp/linux/tools/lib/bpf'

Auto-detecting system features:
...                        libelf: [ on  ]
...                           bpf: [ on  ]

Warning: Kernel ABI header at 'tools/include/uapi/linux/if_link.h' differs from latest version at 'include/uapi/linux/if_link.h'
  CC       /tmp/bpftool/libbpf.o
  CC       /tmp/bpftool/bpf.o
  CC       /tmp/bpftool/nlattr.o
  CC       /tmp/bpftool/btf.o
  CC       /tmp/bpftool/libbpf_errno.o
  LD       /tmp/bpftool/libbpf-in.o
  LINK     /tmp/bpftool/libbpf.a
make[1]: Leaving directory '/tmp/linux/tools/lib/bpf'
  LINK     /tmp/bpftool/bpftool
make: Leaving directory '/tmp/linux/tools/bpf/bpftool'

^ permalink raw reply

* [RFC iproute2-next v1 5/5] tc: Add support for configuring the taprio scheduler
From: Vinicius Costa Gomes @ 2018-07-14  0:06 UTC (permalink / raw)
  To: netdev
  Cc: Vinicius Costa Gomes, jhs, xiyou.wangcong, jiri,
	jesus.sanchez-palencia
In-Reply-To: <20180714000611.1179-1-vinicius.gomes@intel.com>

This traffic scheduler allows traffic classes states (transmission
allowed/not allowed, in the simplest case) to be scheduled, according
to a pre-generated time sequence. This is the basis of the IEEE
802.1Qbv specification.

If the controller supports it, traffic can be also marked as
preemptable/not preemptable, and the states for each entry in the time
sequence gains a couple more commands. This maps to the functionality
defined by the IEEE 802.1Qbu specification.

The syntax is:

tc qdisc add dev DEV parent NODE taprio num_tc NUMBER map P0 P1 ...
	queues TC0 TC1 TC2 ...
	[ [sched-file file] | [sched-row INDEX CMD GATE-MASK INTERVAL]
	[ base-time TIME ] [ extension-time TIME ] [ cycle-time TIME ]
	[ preemption TC0 TC1 TC2 ... ]
	clockid CLOCKID

The parameters should be similar to what the IEEE 802.1Q family of
specification define.

Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
Signed-off-by: Jesus Sanchez-Palencia <jesus.sanchez-palencia@intel.com>
---
 tc/Makefile   |   1 +
 tc/q_taprio.c | 450 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 451 insertions(+)
 create mode 100644 tc/q_taprio.c

diff --git a/tc/Makefile b/tc/Makefile
index dfd00267..6534d69b 100644
--- a/tc/Makefile
+++ b/tc/Makefile
@@ -71,6 +71,7 @@ TCMODULES += q_clsact.o
 TCMODULES += e_bpf.o
 TCMODULES += f_matchall.o
 TCMODULES += q_cbs.o
+TCMODULES += q_taprio.o
 
 TCSO :=
 ifeq ($(TC_CONFIG_ATM),y)
diff --git a/tc/q_taprio.c b/tc/q_taprio.c
new file mode 100644
index 00000000..ef8baa4b
--- /dev/null
+++ b/tc/q_taprio.c
@@ -0,0 +1,450 @@
+/*
+ * q_taprio.c	Time Aware Priority Scheduler
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ *
+ * Authors:	Vinicius Costa Gomes <vinicius.gomes@intel.com>
+ * 		Jesus Sanchez-Palencia <jesus.sanchez-palencia@intel.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+
+#include "utils.h"
+#include "tc_util.h"
+
+#define CLOCKID_INVALID (-1)
+static const struct static_clockid {
+	const char *name;
+	clockid_t clockid;
+} clockids_sysv[] = {
+	{ "REALTIME", CLOCK_REALTIME },
+	{ "TAI", CLOCK_TAI },
+	{ "BOOTTIME", CLOCK_BOOTTIME },
+	{ "MONOTONIC", CLOCK_MONOTONIC },
+	{ NULL }
+};
+
+static void explain(void)
+{
+	fprintf(stderr, "Usage: ... taprio clockid CLOCKID\n");
+	fprintf(stderr, "                  [num_tc NUMBER] [map P0 P1 ...] ");
+	fprintf(stderr, "                  [queues TC0 TC1 TC2 ...] ");
+	fprintf(stderr, "                  [ [sched-file file] | [sched-row index cmd gate-mask interval] ] ");
+	fprintf(stderr, "                  [base-time time] [extension-time time] [cycle-time time] ");
+	fprintf(stderr, "                  [preemption TC0 TC1 TC2 ... ] ");
+	fprintf(stderr, "\nCLOCKID must be a valid SYS-V id (i.e. CLOCK_TAI)");
+	fprintf(stderr, "\n");
+}
+
+static void explain_clockid(const char *val)
+{
+	fprintf(stderr, "taprio: illegal value for \"clockid\": \"%s\".\n", val);
+	fprintf(stderr, "It must be a valid SYS-V id (i.e. CLOCK_TAI)\n");
+}
+
+static int get_clockid(__s32 *val, const char *arg)
+{
+	const struct static_clockid *c;
+
+	/* Drop the CLOCK_ prefix if that is being used. */
+	if (strcasestr(arg, "CLOCK_") != NULL)
+		arg += sizeof("CLOCK_") - 1;
+
+	for (c = clockids_sysv; c->name; c++) {
+		if (strcasecmp(c->name, arg) == 0) {
+			*val = c->clockid;
+
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+static const char* get_clock_name(clockid_t clockid)
+{
+	const struct static_clockid *c;
+
+	for (c = clockids_sysv; c->name; c++) {
+		if (clockid == c->clockid)
+			return c->name;
+	}
+
+	return "invalid";
+}
+
+static int str_to_entry_cmd(const char *str)
+{
+	if (strcmp(str, "S") == 0)
+		return TC_TAPRIO_CMD_SET_GATES;
+
+	if (strcmp(str, "H") == 0)
+		return TC_TAPRIO_CMD_SET_AND_HOLD;
+
+	if (strcmp(str, "R") == 0)
+		return TC_TAPRIO_CMD_SET_AND_RELEASE;
+
+	return -1;
+}
+
+static int add_sched_list(FILE *f, struct nlmsghdr *n)
+{
+	__u32 interval, gatemask, index = 0;
+	char *cmd_str;
+	__u8 cmd;
+	int err;
+
+	while (fscanf(f, "%ms %x %" PRIu32 "\n", &cmd_str, &gatemask, &interval) != EOF)  {
+		struct rtattr *entry;
+
+		err = str_to_entry_cmd(cmd_str);
+		free(cmd_str);
+
+		if (err < 0)
+			return err;
+
+		cmd = err;
+
+		entry = addattr_nest(n, 1024, TCA_TAPRIO_SCHED_ENTRY);
+
+		addattr_l(n, 1024, TCA_TAPRIO_SCHED_ENTRY_INDEX, &index, sizeof(index));
+		addattr_l(n, 1024, TCA_TAPRIO_SCHED_ENTRY_CMD, &cmd, sizeof(cmd));
+		addattr_l(n, 1024, TCA_TAPRIO_SCHED_ENTRY_GATE_MASK, &gatemask, sizeof(gatemask));
+		addattr_l(n, 1024, TCA_TAPRIO_SCHED_ENTRY_INTERVAL, &interval, sizeof(interval));
+
+		addattr_nest_end(n, entry);
+	}
+
+	return 0;
+}
+
+static void explain_sched_row(void)
+{
+	fprintf(stderr, "Usage: ... taprio ... sched-row <index> <cmd> <gate mask> <interval>\n");
+}
+
+static int taprio_parse_opt(struct qdisc_util *qu, int argc,
+			    char **argv, struct nlmsghdr *n, const char *dev)
+{
+	__u32 entry_interval = 0, entry_gatemask = 0, entry_index = 0;
+	__s64 base_time = 0, extension_time = 0, cycle_time = 0;
+	__s32 clockid = CLOCKID_INVALID;
+	struct tc_mqprio_qopt opt = { };
+	unsigned int preemption = 0;
+	FILE *sched_file = NULL;
+	struct rtattr *tail;
+	__u8 entry_cmd = 0;
+	int err, idx;
+
+	while (argc > 0) {
+		idx = 0;
+		if (strcmp(*argv, "num_tc") == 0) {
+			NEXT_ARG();
+			if (get_u8(&opt.num_tc, *argv, 10)) {
+				fprintf(stderr, "Illegal \"num_tc\"\n");
+				return -1;
+			}
+		} else if (strcmp(*argv, "map") == 0) {
+			while (idx < TC_QOPT_MAX_QUEUE && NEXT_ARG_OK()) {
+				NEXT_ARG();
+				if (get_u8(&opt.prio_tc_map[idx], *argv, 10)) {
+					PREV_ARG();
+					break;
+				}
+				idx++;
+			}
+			for ( ; idx < TC_QOPT_MAX_QUEUE; idx++)
+				opt.prio_tc_map[idx] = 0;
+		} else if (strcmp(*argv, "queues") == 0) {
+			char *tmp, *tok;
+
+			while (idx < TC_QOPT_MAX_QUEUE && NEXT_ARG_OK()) {
+				NEXT_ARG();
+
+				tmp = strdup(*argv);
+				if (!tmp)
+					break;
+
+				tok = strtok(tmp, "@");
+				if (get_u16(&opt.count[idx], tok, 10)) {
+					free(tmp);
+					PREV_ARG();
+					break;
+				}
+				tok = strtok(NULL, "@");
+				if (get_u16(&opt.offset[idx], tok, 10)) {
+					free(tmp);
+					PREV_ARG();
+					break;
+				}
+				free(tmp);
+				idx++;
+			}
+		} else if (strcmp(*argv, "sched-file") == 0) {
+			if (entry_index || entry_cmd || entry_gatemask || entry_interval) {
+				fprintf(stderr,
+					"taprio: specifying both \"sched-file\" and \"sched-row\" is not allowed\n");
+				return -1;
+			}
+			NEXT_ARG();
+
+			sched_file = fopen(*argv, "r");
+			if (!sched_file) {
+				break;
+			}
+		} else if (strcmp(*argv, "sched-row") == 0) {
+			if (sched_file) {
+				fprintf(stderr, "taprio: specifying both \"sched-file\" and \"sched-row\" is not allowed\n");
+				return -1;
+			}
+
+			NEXT_ARG();
+
+			if (get_u32(&entry_index, *argv, 10)) {
+				explain_sched_row();
+				return -1;
+			}
+
+			NEXT_ARG();
+			err = str_to_entry_cmd(*argv);
+			if (err < 0) {
+				explain_sched_row();
+				return  -1;
+			}
+			entry_cmd = err;
+
+			NEXT_ARG();
+			if (get_u32(&entry_gatemask, *argv, 0)) {
+				explain_sched_row();
+				return -1;
+			}
+
+			NEXT_ARG();
+			if (get_u32(&entry_interval, *argv, 0)) {
+				explain_sched_row();
+				return -1;
+			}
+		} else if (strcmp(*argv, "base-time") == 0) {
+			NEXT_ARG();
+			if (get_s64(&base_time, *argv, 10)) {
+				PREV_ARG();
+				break;
+			}
+		} else if (strcmp(*argv, "cycle-time") == 0) {
+			NEXT_ARG();
+			if (get_s64(&cycle_time, *argv, 10)) {
+				PREV_ARG();
+				break;
+			}
+		} else if (strcmp(*argv, "extension-time") == 0) {
+			NEXT_ARG();
+			if (get_s64(&extension_time, *argv, 10)) {
+				PREV_ARG();
+				break;
+			}
+		} else if (strcmp(*argv, "preemption") == 0) {
+			__u8 enable;
+			int i;
+
+			for (i = 0; i < opt.num_tc; i++) {
+				NEXT_ARG();
+
+				if (get_u8(&enable, *argv, 0)) {
+					PREV_ARG();
+					break;
+				}
+
+				preemption |= enable ? BIT(i) : 0;
+			}
+		} else if (strcmp(*argv, "clockid") == 0) {
+			NEXT_ARG();
+			if (clockid != CLOCKID_INVALID) {
+				fprintf(stderr, "taprio: duplicate \"clockid\" specification\n");
+				return -1;
+			}
+			if (get_clockid(&clockid, *argv)) {
+				explain_clockid(*argv);
+				return -1;
+			}
+		} else if (strcmp(*argv, "help") == 0) {
+			explain();
+			return -1;
+		} else {
+			fprintf(stderr, "Unknown argument\n");
+			return -1;
+		}
+		argc--; argv++;
+	}
+
+	tail = NLMSG_TAIL(n);
+	addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
+
+	if (opt.num_tc > 0)
+		addattr_l(n, 1024, TCA_TAPRIO_ATTR_PRIOMAP, &opt, sizeof(opt));
+
+	if (preemption)
+		addattr_l(n, 1024, TCA_TAPRIO_ATTR_PREEMPT_MASK, &preemption, sizeof(preemption));
+
+	if (base_time)
+		addattr_l(n, 1024, TCA_TAPRIO_ATTR_SCHED_BASE_TIME, &base_time, sizeof(base_time));
+
+	if (cycle_time)
+		addattr_l(n, 1024, TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME, &cycle_time, sizeof(cycle_time));
+
+	if (extension_time)
+		addattr_l(n, 1024, TCA_TAPRIO_ATTR_SCHED_EXTENSION_TIME, &extension_time, sizeof(extension_time));
+
+	addattr_l(n, 1024, TCA_TAPRIO_ATTR_SCHED_CLOCKID, &clockid, sizeof(clockid));
+
+	if (sched_file) {
+		struct rtattr *entry_list;
+		entry_list = addattr_nest(n, 1024, TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST | NLA_F_NESTED);
+
+		err = add_sched_list(sched_file, n);
+		if (err < 0) {
+			fprintf(stderr, "Could not read sched list from file\n");
+			return -1;
+		}
+
+		addattr_nest_end(n, entry_list);
+	}
+
+	if (entry_index || entry_cmd || entry_gatemask || entry_interval) {
+		struct rtattr *entry, *entry_list;
+
+		entry_list = addattr_nest(n, 1024, TCA_TAPRIO_ATTR_SCHED_SINGLE_ENTRY | NLA_F_NESTED);
+		entry = addattr_nest(n, 1024, TCA_TAPRIO_SCHED_ENTRY);
+
+		addattr_l(n, 1024, TCA_TAPRIO_SCHED_ENTRY_INDEX, &entry_index, sizeof(entry_index));
+		addattr_l(n, 1024, TCA_TAPRIO_SCHED_ENTRY_CMD, &entry_cmd, sizeof(entry_cmd));
+		addattr_l(n, 1024, TCA_TAPRIO_SCHED_ENTRY_GATE_MASK, &entry_gatemask, sizeof(entry_gatemask));
+		addattr_l(n, 1024, TCA_TAPRIO_SCHED_ENTRY_INTERVAL, &entry_interval, sizeof(entry_interval));
+
+		addattr_nest_end(n, entry);
+		addattr_nest_end(n, entry_list);
+	}
+
+	tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
+
+	return 0;
+}
+
+static const char *command_to_str(__u8 cmd)
+{
+	switch (cmd) {
+	case TC_TAPRIO_CMD_SET_GATES:
+		return "S";
+	case TC_TAPRIO_CMD_SET_AND_HOLD:
+		return "H";
+	case TC_TAPRIO_CMD_SET_AND_RELEASE:
+		return "R";
+	default:
+		return "Invalid";
+	}
+}
+
+static int print_sched_list(FILE *f, struct rtattr *list)
+{
+	struct rtattr *item;
+	int rem;
+
+	if (list == NULL)
+		return 0;
+
+	rem = RTA_PAYLOAD(list);
+
+	for (item = RTA_DATA(list); RTA_OK(item, rem); item = RTA_NEXT(item, rem)) {
+		struct rtattr *tb[TCA_TAPRIO_SCHED_ENTRY_MAX + 1];
+		__u32 index = 0, gatemask = 0, interval = 0;
+		__u8 command = 0;
+
+		parse_rtattr_nested(tb, TCA_TAPRIO_SCHED_ENTRY_MAX, item);
+
+		if (tb[TCA_TAPRIO_SCHED_ENTRY_INDEX])
+			index = rta_getattr_u32(tb[TCA_TAPRIO_SCHED_ENTRY_INDEX]);
+
+		if (tb[TCA_TAPRIO_SCHED_ENTRY_CMD])
+			command = rta_getattr_u8(tb[TCA_TAPRIO_SCHED_ENTRY_CMD]);
+
+		if (tb[TCA_TAPRIO_SCHED_ENTRY_GATE_MASK])
+			gatemask = rta_getattr_u32(tb[TCA_TAPRIO_SCHED_ENTRY_GATE_MASK]);
+
+		if (tb[TCA_TAPRIO_SCHED_ENTRY_INTERVAL])
+			interval = rta_getattr_u32(tb[TCA_TAPRIO_SCHED_ENTRY_INTERVAL]);
+
+		fprintf(f, "\n		index %u cmd %s gate-mask 0x%x interval %u", index,
+			command_to_str(command), gatemask, interval);
+	}
+
+	return 0;
+}
+
+static int taprio_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
+{
+	struct rtattr *tb[TCA_TAPRIO_ATTR_MAX + 1];
+	struct tc_mqprio_qopt *qopt = 0;
+	__s64 cycle_time = 0, extension_time = 0, base_time = 0;
+	__s32 clockid = CLOCKID_INVALID;
+	__u32 preempt_mask = 0;
+	int i;
+
+	if (opt == NULL)
+		return 0;
+
+	parse_rtattr_nested(tb, TCA_TAPRIO_ATTR_MAX, opt);
+
+	if (tb[TCA_TAPRIO_ATTR_PRIOMAP] == NULL)
+		return -1;
+
+	qopt = RTA_DATA(tb[TCA_TAPRIO_ATTR_PRIOMAP]);
+
+	fprintf(f, "tc %u map ", qopt->num_tc);
+	for (i = 0; i <= TC_PRIO_MAX; i++)
+		fprintf(f, "%u ", qopt->prio_tc_map[i]);
+	fprintf(f, "\n	queues:");
+	for (i = 0; i < qopt->num_tc; i++)
+		fprintf(f, "(%u:%u) ", qopt->offset[i],
+			qopt->offset[i] + qopt->count[i] - 1);
+
+	if (tb[TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME])
+		cycle_time = rta_getattr_s64(tb[TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME]);
+
+	if (tb[TCA_TAPRIO_ATTR_SCHED_EXTENSION_TIME])
+		extension_time = rta_getattr_s64(tb[TCA_TAPRIO_ATTR_SCHED_EXTENSION_TIME]);
+
+	if (tb[TCA_TAPRIO_ATTR_SCHED_BASE_TIME])
+		base_time = rta_getattr_s64(tb[TCA_TAPRIO_ATTR_SCHED_BASE_TIME]);
+
+	if (tb[TCA_TAPRIO_ATTR_PREEMPT_MASK])
+		preempt_mask = rta_getattr_s64(tb[TCA_TAPRIO_ATTR_PREEMPT_MASK]);
+
+	if (tb[TCA_TAPRIO_ATTR_SCHED_CLOCKID])
+		clockid = rta_getattr_s32(tb[TCA_TAPRIO_ATTR_SCHED_CLOCKID]);
+
+	fprintf(f, "\n	clockid %s ", get_clock_name(clockid));
+
+	fprintf(f, "\n	base-time %lld cycle-time %lld extension-time %lld ",
+		base_time, cycle_time, extension_time);
+
+	fprintf(f, "\n	preempt-mask 0x%x ", preempt_mask);
+
+	return print_sched_list(f, tb[TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST]);
+}
+
+struct qdisc_util taprio_qdisc_util = {
+	.id		= "taprio",
+	.parse_qopt	= taprio_parse_opt,
+	.print_qopt	= taprio_print_opt,
+};
-- 
2.18.0

^ permalink raw reply related

* [RFC iproute2-next v1 4/5] include: add definitions for taprio [DO NOT COMMIT]
From: Vinicius Costa Gomes @ 2018-07-14  0:06 UTC (permalink / raw)
  To: netdev
  Cc: Vinicius Costa Gomes, jhs, xiyou.wangcong, jiri,
	jesus.sanchez-palencia
In-Reply-To: <20180714000611.1179-1-vinicius.gomes@intel.com>

DO NOT COMMIT

This patch exists only to ease the testing, until this header is
updated with the definitions from the kernel.

Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
---
 include/uapi/linux/pkt_sched.h | 48 ++++++++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)

diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h
index 37b5096a..8ca988cb 100644
--- a/include/uapi/linux/pkt_sched.h
+++ b/include/uapi/linux/pkt_sched.h
@@ -934,4 +934,52 @@ enum {
 
 #define TCA_CBS_MAX (__TCA_CBS_MAX - 1)
 
+/* TAPRIO */
+enum {
+	TC_TAPRIO_CMD_SET_GATES = 0x00,
+	TC_TAPRIO_CMD_SET_AND_HOLD = 0x01,
+	TC_TAPRIO_CMD_SET_AND_RELEASE = 0x02,
+};
+
+enum {
+	TCA_TAPRIO_SCHED_ENTRY_UNSPEC,
+	TCA_TAPRIO_SCHED_ENTRY_INDEX, /* u32 */
+	TCA_TAPRIO_SCHED_ENTRY_CMD, /* u8 */
+	TCA_TAPRIO_SCHED_ENTRY_GATE_MASK, /* u32 */
+	TCA_TAPRIO_SCHED_ENTRY_INTERVAL, /* u32 */
+	__TCA_TAPRIO_SCHED_ENTRY_MAX,
+};
+#define TCA_TAPRIO_SCHED_ENTRY_MAX (__TCA_TAPRIO_SCHED_ENTRY_MAX - 1)
+
+/* The format for schedule entry list is:
+ * [TCA_TAPRIO_SCHED_ENTRY_LIST]
+ *   [TCA_TAPRIO_SCHED_ENTRY]
+ *     [TCA_TAPRIO_SCHED_ENTRY_CMD]
+ *     [TCA_TAPRIO_SCHED_ENTRY_GATES]
+ *     [TCA_TAPRIO_SCHED_ENTRY_INTERVAL]
+ */
+enum {
+	TCA_TAPRIO_SCHED_UNSPEC,
+	TCA_TAPRIO_SCHED_ENTRY,
+	__TCA_TAPRIO_SCHED_MAX,
+};
+
+#define TCA_TAPRIO_SCHED_MAX (__TCA_TAPRIO_SCHED_MAX - 1)
+
+enum {
+	TCA_TAPRIO_ATTR_UNSPEC,
+	TCA_TAPRIO_ATTR_PRIOMAP, /* struct tc_mqprio_qopt */
+	TCA_TAPRIO_ATTR_PREEMPT_MASK, /* which traffic classes are preemptible, u32 */
+	TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST, /* nested of entry */
+	TCA_TAPRIO_ATTR_SCHED_BASE_TIME, /* s64 */
+	TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME, /* s64 */
+	TCA_TAPRIO_ATTR_SCHED_EXTENSION_TIME, /* s64 */
+	TCA_TAPRIO_ATTR_SCHED_SINGLE_ENTRY, /*  */
+	TCA_TAPRIO_ATTR_SCHED_CLOCKID, /* s32 */
+	TCA_TAPRIO_PAD,
+	__TCA_TAPRIO_ATTR_MAX,
+};
+
+#define TCA_TAPRIO_ATTR_MAX (__TCA_TAPRIO_ATTR_MAX - 1)
+
 #endif
-- 
2.18.0

^ permalink raw reply related

* [RFC iproute2-next v1 3/5] libnetlink: Add helper for getting a __s32 from netlink msgs
From: Vinicius Costa Gomes @ 2018-07-14  0:06 UTC (permalink / raw)
  To: netdev; +Cc: Jesus Sanchez-Palencia, jhs, xiyou.wangcong, jiri
In-Reply-To: <20180714000611.1179-1-vinicius.gomes@intel.com>

From: Jesus Sanchez-Palencia <jesus.sanchez-palencia@intel.com>

This function retrieves a signed 32-bit integer from a netlink message
and returns it.

Signed-off-by: Jesus Sanchez-Palencia <jesus.sanchez-palencia@intel.com>
---
 include/libnetlink.h | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/include/libnetlink.h b/include/libnetlink.h
index 88164975..114a816e 100644
--- a/include/libnetlink.h
+++ b/include/libnetlink.h
@@ -185,6 +185,13 @@ static inline __u64 rta_getattr_u64(const struct rtattr *rta)
 	memcpy(&tmp, RTA_DATA(rta), sizeof(__u64));
 	return tmp;
 }
+static inline __s32 rta_getattr_s32(const struct rtattr *rta)
+{
+	__s32 tmp;
+
+	memcpy(&tmp, RTA_DATA(rta), sizeof(__s32));
+	return tmp;
+}
 static inline __s64 rta_getattr_s64(const struct rtattr *rta)
 {
 	__s64 tmp;
-- 
2.18.0

^ permalink raw reply related

* [RFC iproute2-next v1 2/5] include: Add helper to retrieve a __s64 from a netlink msg
From: Vinicius Costa Gomes @ 2018-07-14  0:06 UTC (permalink / raw)
  To: netdev
  Cc: Vinicius Costa Gomes, jhs, xiyou.wangcong, jiri,
	jesus.sanchez-palencia
In-Reply-To: <20180714000611.1179-1-vinicius.gomes@intel.com>

This allows signed 64-bit integers to be retrieved from a netlink
message.
---
 include/libnetlink.h | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/include/libnetlink.h b/include/libnetlink.h
index 9d9249e6..88164975 100644
--- a/include/libnetlink.h
+++ b/include/libnetlink.h
@@ -185,6 +185,13 @@ static inline __u64 rta_getattr_u64(const struct rtattr *rta)
 	memcpy(&tmp, RTA_DATA(rta), sizeof(__u64));
 	return tmp;
 }
+static inline __s64 rta_getattr_s64(const struct rtattr *rta)
+{
+	__s64 tmp;
+
+	memcpy(&tmp, RTA_DATA(rta), sizeof(__s64));
+	return tmp;
+}
 static inline const char *rta_getattr_str(const struct rtattr *rta)
 {
 	return (const char *)RTA_DATA(rta);
-- 
2.18.0

^ permalink raw reply related

* [RFC iproute2-next v1 1/5] utils: Implement get_s64()
From: Vinicius Costa Gomes @ 2018-07-14  0:06 UTC (permalink / raw)
  To: netdev
  Cc: Vinicius Costa Gomes, jhs, xiyou.wangcong, jiri,
	jesus.sanchez-palencia
In-Reply-To: <20180714000611.1179-1-vinicius.gomes@intel.com>

Add this helper to read signed 64-bit integers from a string.
---
 include/utils.h |  1 +
 lib/utils.c     | 21 +++++++++++++++++++++
 2 files changed, 22 insertions(+)

diff --git a/include/utils.h b/include/utils.h
index 8cb4349e..58574a05 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -139,6 +139,7 @@ int get_time_rtt(unsigned *val, const char *arg, int *raw);
 #define get_byte get_u8
 #define get_ushort get_u16
 #define get_short get_s16
+int get_s64(__s64 *val, const char *arg, int base);
 int get_u64(__u64 *val, const char *arg, int base);
 int get_u32(__u32 *val, const char *arg, int base);
 int get_s32(__s32 *val, const char *arg, int base);
diff --git a/lib/utils.c b/lib/utils.c
index 02ce6772..02836d6e 100644
--- a/lib/utils.c
+++ b/lib/utils.c
@@ -382,6 +382,27 @@ int get_u8(__u8 *val, const char *arg, int base)
 	return 0;
 }
 
+int get_s64(__s64 *val, const char *arg, int base)
+{
+	long res;
+	char *ptr;
+
+	errno = 0;
+
+	if (!arg || !*arg)
+		return -1;
+	res = strtoll(arg, &ptr, base);
+	if (!ptr || ptr == arg || *ptr)
+		return -1;
+	if ((res == LLONG_MIN || res == LLONG_MAX) && errno == ERANGE)
+		return -1;
+	if (res > INT64_MAX || res < INT64_MIN)
+		return -1;
+
+	*val = res;
+	return 0;
+}
+
 int get_s32(__s32 *val, const char *arg, int base)
 {
 	long res;
-- 
2.18.0

^ permalink raw reply related

* [RFC iproute2-next v1 0/5] net/sched: Introduce the taprio scheduler
From: Vinicius Costa Gomes @ 2018-07-14  0:06 UTC (permalink / raw)
  To: netdev
  Cc: Vinicius Costa Gomes, jhs, xiyou.wangcong, jiri,
	jesus.sanchez-palencia

Hi,

This is iproute2 side of the taprio RFC series.

Please see the kernel side cover letter for more information about how
to test this.


Cheers,

^ permalink raw reply

* [RFC net-next v1 1/1] net/sched: Introduce the taprio scheduler
From: Vinicius Costa Gomes @ 2018-07-14  0:05 UTC (permalink / raw)
  To: netdev
  Cc: Vinicius Costa Gomes, jesus.sanchez-palencia, tglx, jan.altenberg,
	henrik, richardcochran, levi.pearson, jhs, xiyou.wangcong, jiri
In-Reply-To: <20180714000536.1008-1-vinicius.gomes@intel.com>

This scheduler allows the network administrator to configure schedules
for classes of traffic, the configuration interface is similar to what
IEEE 802.1Qbv-2015 defines.

Example configuration:

$ tc qdisc add dev enp2s0 parent root handle 100 taprio \
     	    num_tc 3 \
	    map 2 2 1 0 2 2 2 2 2 2 2 2 2 2 2 2 \
	    queues 1@0 1@1 2@2 \
	    sched-file ~/gates.sched \
	    base-time 1000000 \
	    clockid CLOCK_TAI

This qdisc borrows a few concepts from mqprio and most the parameters
are similar to mqprio. The main difference is the 'sched-file'
parameter, one example of a schedule file would be:

gates.sched
-----------
S 01 300000
S 02 300000
S 04 300000

The format of each line is:
<CMD> <GATE MASK> <INTERVAL>

The only supported <CMD> is "S", which means "SetGateStates",
following the IEEE 802.1Qbv-2015 definition (Table 8-6). <GATE MASK>
is a bitmask where each bit is a associated with a traffic class, so
bit 0 (the least significant bit) being "on" means that traffic class
0 is "active" for that schedule entry. <INTERVAL> is a time duration
in nanoseconds that specifies for how long that state defined by <CMD>
and <GATE MASK> should be held before moving to the next entry.

This schedule is circular, that is, after the last entry is executed
it starts from the first one, indefinitely.

The other parameters can be defined as follows:
 - base-time: allows that multiple systems can have synchronized
 schedules, it specifies the instant when the schedule starts;
 - clockid: specifies the reference clock to be used;

Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
---
 include/uapi/linux/pkt_sched.h |  49 ++
 net/sched/Kconfig              |  11 +
 net/sched/Makefile             |   1 +
 net/sched/sch_taprio.c         | 952 +++++++++++++++++++++++++++++++++
 4 files changed, 1013 insertions(+)
 create mode 100644 net/sched/sch_taprio.c

diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h
index d9cc9dc4f547..863df790ff07 100644
--- a/include/uapi/linux/pkt_sched.h
+++ b/include/uapi/linux/pkt_sched.h
@@ -1069,4 +1069,53 @@ enum {
 	CAKE_ATM_MAX
 };
 
+
+/* TAPRIO */
+enum {
+	TC_TAPRIO_CMD_SET_GATES = 0x00,
+	TC_TAPRIO_CMD_SET_AND_HOLD = 0x01,
+	TC_TAPRIO_CMD_SET_AND_RELEASE = 0x02,
+};
+
+enum {
+	TCA_TAPRIO_SCHED_ENTRY_UNSPEC,
+	TCA_TAPRIO_SCHED_ENTRY_INDEX, /* u32 */
+	TCA_TAPRIO_SCHED_ENTRY_CMD, /* u8 */
+	TCA_TAPRIO_SCHED_ENTRY_GATE_MASK, /* u32 */
+	TCA_TAPRIO_SCHED_ENTRY_INTERVAL, /* u32 */
+	__TCA_TAPRIO_SCHED_ENTRY_MAX,
+};
+#define TCA_TAPRIO_SCHED_ENTRY_MAX (__TCA_TAPRIO_SCHED_ENTRY_MAX - 1)
+
+/* The format for schedule entry list is:
+ * [TCA_TAPRIO_SCHED_ENTRY_LIST]
+ *   [TCA_TAPRIO_SCHED_ENTRY]
+ *     [TCA_TAPRIO_SCHED_ENTRY_CMD]
+ *     [TCA_TAPRIO_SCHED_ENTRY_GATES]
+ *     [TCA_TAPRIO_SCHED_ENTRY_INTERVAL]
+ */
+enum {
+	TCA_TAPRIO_SCHED_UNSPEC,
+	TCA_TAPRIO_SCHED_ENTRY,
+	__TCA_TAPRIO_SCHED_MAX,
+};
+
+#define TCA_TAPRIO_SCHED_MAX (__TCA_TAPRIO_SCHED_MAX - 1)
+
+enum {
+	TCA_TAPRIO_ATTR_UNSPEC,
+	TCA_TAPRIO_ATTR_PRIOMAP, /* struct tc_mqprio_qopt */
+	TCA_TAPRIO_ATTR_PREEMPT_MASK, /* which traffic classes are preemptible, u32 */
+	TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST, /* nested of entry */
+	TCA_TAPRIO_ATTR_SCHED_BASE_TIME, /* s64 */
+	TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME, /* s64 */
+	TCA_TAPRIO_ATTR_SCHED_EXTENSION_TIME, /* s64 */
+	TCA_TAPRIO_ATTR_SCHED_SINGLE_ENTRY, /* single entry */
+	TCA_TAPRIO_ATTR_SCHED_CLOCKID, /* s32 */
+	TCA_TAPRIO_PAD,
+	__TCA_TAPRIO_ATTR_MAX,
+};
+
+#define TCA_TAPRIO_ATTR_MAX (__TCA_TAPRIO_ATTR_MAX - 1)
+
 #endif
diff --git a/net/sched/Kconfig b/net/sched/Kconfig
index 7af246764a35..e728d2e3052b 100644
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -194,6 +194,17 @@ config NET_SCH_ETF
 	  To compile this code as a module, choose M here: the
 	  module will be called sch_etf.
 
+config NET_SCH_TAPRIO
+	tristate "Time Aware Priority (taprio) Scheduler"
+	help
+	  Say Y here if you want to use the Time Aware Priority (taprio) packet
+	  scheduling algorithm.
+
+	  See the top of <file:net/sched/sch_taprio.c> for more details.
+
+	  To compile this code as a module, choose M here: the
+	  module will be called sch_taprio.
+
 config NET_SCH_GRED
 	tristate "Generic Random Early Detection (GRED)"
 	---help---
diff --git a/net/sched/Makefile b/net/sched/Makefile
index 673ee7d26ff2..dc81a16e35b5 100644
--- a/net/sched/Makefile
+++ b/net/sched/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_NET_SCH_HHF)	+= sch_hhf.o
 obj-$(CONFIG_NET_SCH_PIE)	+= sch_pie.o
 obj-$(CONFIG_NET_SCH_CBS)	+= sch_cbs.o
 obj-$(CONFIG_NET_SCH_ETF)	+= sch_etf.o
+obj-$(CONFIG_NET_SCH_TAPRIO)	+= sch_taprio.o
 
 obj-$(CONFIG_NET_CLS_U32)	+= cls_u32.o
 obj-$(CONFIG_NET_CLS_ROUTE4)	+= cls_route.o
diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c
new file mode 100644
index 000000000000..4dd0337a2e8c
--- /dev/null
+++ b/net/sched/sch_taprio.c
@@ -0,0 +1,952 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* net/sched/sch_taprio.c	 Time Aware Priority Scheduler
+ *
+ * Authors:	Vinicius Costa Gomes <vinicius.gomes@intel.com>
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+#include <linux/module.h>
+#include <net/netlink.h>
+#include <net/pkt_sched.h>
+#include <net/pkt_cls.h>
+#include <net/sch_generic.h>
+
+#define TAPRIO_ALL_GATES_OPEN -1
+
+struct sched_entry {
+	struct list_head list;
+	int index;
+	u32 gate_mask;
+	u32 interval;
+	u8 command;
+};
+
+struct taprio_sched {
+	struct Qdisc **qdiscs;
+	struct Qdisc *root;
+	s64 base_time;
+	s64 cycle_time;
+	s64 extension_time;
+	u32 preempt_mask;
+	size_t num_entries;
+	ktime_t current_expires;
+	ktime_t next_cycle_start;
+	int picos_per_byte;
+	spinlock_t current_entry_lock; /* Protects writing to current_entry */
+	struct sched_entry __rcu *current_entry;
+	atomic_t budget;
+	struct list_head entries;
+	struct hrtimer advance_timer;
+	int clockid;
+	ktime_t (*get_time)(void);
+};
+
+static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch,
+			  struct sk_buff **to_free)
+{
+	struct taprio_sched *q = qdisc_priv(sch);
+	struct Qdisc *child;
+	int queue;
+
+	queue = skb_get_queue_mapping(skb);
+
+	child = q->qdiscs[queue];
+	if (unlikely(!child))
+		return qdisc_drop(skb, sch, to_free);
+
+	qdisc_qstats_backlog_inc(sch, skb);
+	sch->q.qlen++;
+
+	return qdisc_enqueue(skb, child, to_free);
+}
+
+static struct sk_buff *taprio_peek(struct Qdisc *sch)
+{
+	struct taprio_sched *q = qdisc_priv(sch);
+	struct net_device *dev = qdisc_dev(sch);
+	struct sched_entry *entry;
+	struct sk_buff *skb;
+	u32 gate_mask;
+	int i;
+
+	rcu_read_lock();
+	entry = rcu_dereference(q->current_entry);
+	gate_mask = entry ? entry->gate_mask : -1;
+	rcu_read_unlock();
+
+	if (!gate_mask)
+		return NULL;
+
+	for (i = 0; i < dev->num_tx_queues; i++) {
+		struct Qdisc *child = q->qdiscs[i];
+		int prio;
+		u8 tc;
+
+		if (unlikely(!child))
+			continue;
+
+		skb = child->ops->peek(child);
+		if (!skb)
+			continue;
+
+		prio = skb->priority;
+		tc = netdev_get_prio_tc_map(dev, prio);
+
+		if (!(gate_mask & BIT(tc)))
+			return NULL;
+
+		return skb;
+	}
+
+	return NULL;
+}
+
+static inline int length_to_duration(struct taprio_sched *q, int len)
+{
+	return (len * q->picos_per_byte) / 1000;
+}
+
+static struct sk_buff *taprio_dequeue(struct Qdisc *sch)
+{
+	struct taprio_sched *q = qdisc_priv(sch);
+	struct net_device *dev = qdisc_dev(sch);
+	struct sched_entry *entry;
+	struct sk_buff *skb;
+	u32 gate_mask;
+	int i;
+
+	rcu_read_lock();
+	entry = rcu_dereference(q->current_entry);
+	/* if there's no entry, it means that the schedule didn't
+	 * start yet, so force all gates to be open, this is in
+	 * accordance to IEEE 802.1Qbv-2015 Section 8.6.9.4.5
+	 * "AdminGateSates"
+	 */
+	gate_mask = entry ? entry->gate_mask : TAPRIO_ALL_GATES_OPEN;
+	rcu_read_unlock();
+
+	if (!gate_mask)
+		return NULL;
+
+	for (i = 0; i < dev->num_tx_queues; i++) {
+		struct Qdisc *child = q->qdiscs[i];
+		ktime_t guard;
+		int prio;
+		int len;
+		u8 tc;
+
+		if (unlikely(!child))
+			continue;
+
+		skb = child->ops->peek(child);
+		if (!skb)
+			continue;
+
+		prio = skb->priority;
+		tc = netdev_get_prio_tc_map(dev, prio);
+
+		if (!(gate_mask & BIT(tc)))
+			continue;
+
+		len = qdisc_pkt_len(skb);
+		guard = q->get_time() + length_to_duration(q, len);
+
+		/* In the case that there's no gate entry, there's no
+		 * guard band ...
+		 */
+		if (gate_mask != TAPRIO_ALL_GATES_OPEN &&
+		    ktime_after(guard, q->current_expires))
+			return NULL;
+
+		/* ... and no budget. */
+		if (gate_mask != TAPRIO_ALL_GATES_OPEN &&
+		    atomic_sub_return(len, &q->budget) < 0)
+			return NULL;
+
+		skb = child->ops->dequeue(child);
+		if (unlikely(!skb))
+			return NULL;
+
+		qdisc_bstats_update(sch, skb);
+		qdisc_qstats_backlog_dec(sch, skb);
+		sch->q.qlen--;
+
+		return skb;
+	}
+
+	return NULL;
+}
+
+static bool should_restart_cycle(struct taprio_sched *q,
+				 struct sched_entry *entry)
+{
+	if (list_is_last(&entry->list, &q->entries))
+		return true;
+
+	if (q->current_expires == q->next_cycle_start)
+		return true;
+
+	return false;
+}
+
+static enum hrtimer_restart advance_sched(struct hrtimer *timer)
+{
+	struct taprio_sched *q = container_of(timer, struct taprio_sched,
+					      advance_timer);
+	struct sched_entry *entry, *next;
+	struct Qdisc *sch = q->root;
+	ktime_t expires;
+
+	spin_lock(&q->current_entry_lock);
+	entry = rcu_dereference_protected(q->current_entry,
+					  lockdep_is_held(&q->current_entry_lock));
+
+	if (!entry || should_restart_cycle(q, entry)) {
+		next = list_first_entry(&q->entries, struct sched_entry,
+					list);
+
+		/* If we come to the end of a cycle, update the start
+		 * of a next cycle
+		 */
+		if (q->current_expires <= q->next_cycle_start)
+			q->next_cycle_start += q->cycle_time;
+	} else {
+		next = list_next_entry(entry, list);
+	}
+
+	expires = ktime_add_ns(q->current_expires, next->interval);
+	expires = min_t(ktime_t, q->next_cycle_start, expires);
+
+	rcu_assign_pointer(q->current_entry, next);
+	q->current_expires = expires;
+	atomic_set(&q->budget, (next->interval * 1000) / q->picos_per_byte);
+
+	spin_unlock(&q->current_entry_lock);
+
+	hrtimer_set_expires(&q->advance_timer, expires);
+
+	rcu_read_lock();
+	__netif_schedule(sch);
+	rcu_read_unlock();
+
+	return HRTIMER_RESTART;
+}
+
+static const struct nla_policy entry_policy[TCA_TAPRIO_SCHED_ENTRY_MAX + 1] = {
+	[TCA_TAPRIO_SCHED_ENTRY_INDEX]	   = { .type = NLA_U32 },
+	[TCA_TAPRIO_SCHED_ENTRY_CMD]	   = { .type = NLA_U8 },
+	[TCA_TAPRIO_SCHED_ENTRY_GATE_MASK] = { .type = NLA_U32 },
+	[TCA_TAPRIO_SCHED_ENTRY_INTERVAL]  = { .type = NLA_U32 },
+};
+
+static const struct nla_policy entry_list_policy[TCA_TAPRIO_SCHED_MAX + 1] = {
+	[TCA_TAPRIO_SCHED_ENTRY] = { .type = NLA_NESTED },
+};
+
+static const struct nla_policy taprio_policy[TCA_TAPRIO_ATTR_MAX + 1] = {
+	[TCA_TAPRIO_ATTR_PRIOMAP]	       = {
+		.len = sizeof(struct tc_mqprio_qopt)
+	},
+	[TCA_TAPRIO_ATTR_PREEMPT_MASK]	       = { .type = NLA_U32 },
+	[TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST]     = { .type = NLA_NESTED },
+	[TCA_TAPRIO_ATTR_SCHED_BASE_TIME]      = { .type = NLA_S64 },
+	[TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME]     = { .type = NLA_S64 },
+	[TCA_TAPRIO_ATTR_SCHED_EXTENSION_TIME] = { .type = NLA_S64 },
+	[TCA_TAPRIO_ATTR_SCHED_SINGLE_ENTRY]   = { .type = NLA_NESTED },
+	[TCA_TAPRIO_ATTR_SCHED_CLOCKID]        = { .type = NLA_S32 },
+};
+
+static int parse_sched_entry(struct nlattr *n, struct sched_entry *entry,
+			     int index)
+{
+	struct nlattr *tb[TCA_TAPRIO_SCHED_ENTRY_MAX + 1] = { };
+	int err;
+
+	err = nla_parse_nested(tb, TCA_TAPRIO_SCHED_ENTRY_MAX, n,
+			       entry_policy, NULL);
+	if (err < 0) {
+		pr_err("Could not parse nested entry");
+		return -EINVAL;
+	}
+
+	entry->index = index;
+
+	if (tb[TCA_TAPRIO_SCHED_ENTRY_CMD])
+		entry->command = nla_get_u8(tb[TCA_TAPRIO_SCHED_ENTRY_CMD]);
+
+	if (tb[TCA_TAPRIO_SCHED_ENTRY_GATE_MASK])
+		entry->gate_mask = nla_get_u32(
+			tb[TCA_TAPRIO_SCHED_ENTRY_GATE_MASK]);
+
+	if (tb[TCA_TAPRIO_SCHED_ENTRY_INTERVAL])
+		entry->interval = nla_get_u32(
+			tb[TCA_TAPRIO_SCHED_ENTRY_INTERVAL]);
+
+	return 0;
+}
+
+static int parse_sched_single_entry(struct nlattr *n,
+				    struct taprio_sched *q)
+{
+	struct nlattr *tb_entry[TCA_TAPRIO_SCHED_ENTRY_MAX + 1] = { };
+	struct nlattr *tb_list[TCA_TAPRIO_SCHED_MAX + 1] = { };
+	struct sched_entry *entry;
+	bool found = false;
+	u32 index;
+	int err;
+
+	err = nla_parse_nested(tb_list, TCA_TAPRIO_SCHED_MAX,
+			       n, entry_list_policy, NULL);
+	if (err < 0) {
+		pr_err("Could not parse nested entry");
+		return -EINVAL;
+	}
+
+	if (!tb_list[TCA_TAPRIO_SCHED_ENTRY]) {
+		pr_err("Single-entry must include an entry\n");
+		return -EINVAL;
+	}
+
+	err = nla_parse_nested(tb_entry, TCA_TAPRIO_SCHED_ENTRY_MAX,
+			       tb_list[TCA_TAPRIO_SCHED_ENTRY],
+			       entry_policy, NULL);
+	if (err < 0) {
+		pr_err("Could not parse nested entry");
+		return -EINVAL;
+	}
+
+	if (!tb_entry[TCA_TAPRIO_SCHED_ENTRY_INDEX]) {
+		pr_err("Entry must specify an index\n");
+		return -EINVAL;
+	}
+
+	index = nla_get_u32(tb_entry[TCA_TAPRIO_SCHED_ENTRY_INDEX]);
+	if (index >= q->num_entries) {
+		pr_err("Invalid index for single entry %d (max %zu)\n",
+		       index, q->num_entries);
+		return -EINVAL;
+	}
+
+	list_for_each_entry(entry, &q->entries, list) {
+		if (entry->index == index) {
+			found = true;
+			break;
+		}
+	}
+
+	if (!found) {
+		pr_err("Could not find entry with index '%d'\n", index);
+		return -ENOENT;
+	}
+
+	if (tb_entry[TCA_TAPRIO_SCHED_ENTRY_CMD])
+		entry->command = nla_get_u8(
+			tb_entry[TCA_TAPRIO_SCHED_ENTRY_CMD]);
+
+	if (tb_entry[TCA_TAPRIO_SCHED_ENTRY_GATE_MASK])
+		entry->gate_mask = nla_get_u32(
+			tb_entry[TCA_TAPRIO_SCHED_ENTRY_GATE_MASK]);
+
+	if (tb_entry[TCA_TAPRIO_SCHED_ENTRY_INTERVAL])
+		entry->interval = nla_get_u32(
+			tb_entry[TCA_TAPRIO_SCHED_ENTRY_INTERVAL]);
+
+	return 0;
+}
+
+static int parse_sched_list(struct nlattr *list,
+			    struct taprio_sched *q)
+{
+	struct nlattr *n;
+	int err, rem;
+	int i = 0;
+
+	if (!list)
+		return -EINVAL;
+
+	nla_for_each_nested(n, list, rem) {
+		struct sched_entry *entry;
+
+		if (nla_type(n) != TCA_TAPRIO_SCHED_ENTRY) {
+			pr_err("Invalid type parsing sched entries %x",
+			       nla_type(n));
+			continue;
+		}
+
+		entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+		if (!entry)
+			return -ENOMEM;
+
+		err = parse_sched_entry(n, entry, i);
+		if (err < 0) {
+			kfree(entry);
+			return err;
+		}
+
+		list_add_tail(&entry->list, &q->entries);
+		i++;
+	}
+
+	q->num_entries = i;
+
+	return i;
+}
+
+static int parse_taprio_opt(struct nlattr **tb, struct taprio_sched *q,
+			    struct netlink_ext_ack *extack)
+{
+	int err = 0;
+	int clockid;
+
+	if (tb[TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST] &&
+	    tb[TCA_TAPRIO_ATTR_SCHED_SINGLE_ENTRY])
+		return -EINVAL;
+
+	if (tb[TCA_TAPRIO_ATTR_SCHED_SINGLE_ENTRY] && q->num_entries == 0)
+		return -EINVAL;
+
+	if (q->clockid == -1 && !tb[TCA_TAPRIO_ATTR_SCHED_CLOCKID])
+		return -EINVAL;
+
+	if (tb[TCA_TAPRIO_ATTR_PREEMPT_MASK])
+		q->preempt_mask = nla_get_u32(
+			tb[TCA_TAPRIO_ATTR_PREEMPT_MASK]);
+
+	if (tb[TCA_TAPRIO_ATTR_SCHED_BASE_TIME])
+		q->base_time = nla_get_s64(
+			tb[TCA_TAPRIO_ATTR_SCHED_BASE_TIME]);
+
+	if (tb[TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME])
+		q->cycle_time = nla_get_s64(
+			tb[TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME]);
+
+	if (tb[TCA_TAPRIO_ATTR_SCHED_EXTENSION_TIME])
+		q->extension_time = nla_get_s64(
+			tb[TCA_TAPRIO_ATTR_SCHED_EXTENSION_TIME]);
+
+	if (tb[TCA_TAPRIO_ATTR_SCHED_CLOCKID]) {
+		clockid = nla_get_s32(tb[TCA_TAPRIO_ATTR_SCHED_CLOCKID]);
+
+		/* We only support static clockids and we don't allow
+		 * for it to be modified after the first init.
+		 */
+		if (clockid < 0 || (q->clockid != -1 && q->clockid != clockid))
+			return -EINVAL;
+
+		q->clockid = clockid;
+	}
+
+	if (tb[TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST])
+		err = parse_sched_list(
+			tb[TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST], q);
+	else if (tb[TCA_TAPRIO_ATTR_SCHED_SINGLE_ENTRY])
+		err = parse_sched_single_entry(
+			tb[TCA_TAPRIO_ATTR_SCHED_SINGLE_ENTRY], q);
+
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static int taprio_parse_mqprio_opt(struct net_device *dev,
+				   struct tc_mqprio_qopt *qopt,
+				   struct netlink_ext_ack *extack)
+{
+	int i, j;
+
+	if (!qopt)
+		return -EINVAL;
+
+	/* Verify num_tc is not out of max range */
+	if (qopt->num_tc > TC_MAX_QUEUE)
+		return -EINVAL;
+
+	/* taprio imposes that traffic classes map 1:1 to tx queues */
+	if (qopt->num_tc > dev->num_tx_queues)
+		return -EINVAL;
+
+	/* Verify priority mapping uses valid tcs */
+	for (i = 0; i < TC_BITMASK + 1; i++) {
+		if (qopt->prio_tc_map[i] >= qopt->num_tc)
+			return -EINVAL;
+	}
+
+	for (i = 0; i < qopt->num_tc; i++) {
+		unsigned int last = qopt->offset[i] + qopt->count[i];
+
+		/* Verify the queue count is in tx range being equal to the
+		 * real_num_tx_queues indicates the last queue is in use.
+		 */
+		if (qopt->offset[i] >= dev->num_tx_queues ||
+		    !qopt->count[i] ||
+		    last > dev->real_num_tx_queues)
+			return -EINVAL;
+
+		/* Verify that the offset and counts do not overlap */
+		for (j = i + 1; j < qopt->num_tc; j++) {
+			if (last > qopt->offset[j])
+				return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static ktime_t taprio_get_first_expires(struct Qdisc *sch)
+{
+	struct taprio_sched *q = qdisc_priv(sch);
+	struct sched_entry *entry;
+	ktime_t now, base, cycle;
+	s64 n;
+
+	base = ns_to_ktime(q->base_time);
+	cycle = q->cycle_time;
+
+	/* If we don't have a cycle_time, we calculate one, by summing
+	 * all the intervals.
+	 */
+	if (!cycle) {
+		list_for_each_entry(entry, &q->entries, list) {
+			cycle = ktime_add_ns(cycle, entry->interval);
+		}
+		q->cycle_time = cycle;
+	}
+
+	if (!cycle)
+		return base;
+
+	now = q->get_time();
+
+	if (ktime_after(base, now))
+		return base;
+
+	/* Schedule the next expiration for the beginning of the next
+	 * cycle.
+	 */
+	n = div64_s64(ktime_sub_ns(now, base), cycle);
+
+	return ktime_add_ns(base, (n + 1) * cycle);
+}
+
+static int taprio_change(struct Qdisc *sch, struct nlattr *opt,
+			 struct netlink_ext_ack *extack)
+{
+	struct nlattr *tb[TCA_TAPRIO_ATTR_MAX + 1] = { };
+	struct taprio_sched *q = qdisc_priv(sch);
+	struct net_device *dev = qdisc_dev(sch);
+	struct tc_mqprio_qopt *mqprio = NULL;
+	struct ethtool_link_ksettings ecmd;
+	s64 link_speed;
+	int i, err, size;
+	ktime_t expires;
+
+	err = nla_parse_nested(tb, TCA_TAPRIO_ATTR_MAX, opt,
+			       taprio_policy, extack);
+	if (err < 0)
+		return err;
+
+	err = -EINVAL;
+	if (tb[TCA_TAPRIO_ATTR_PRIOMAP])
+		mqprio = nla_data(tb[TCA_TAPRIO_ATTR_PRIOMAP]);
+
+	err = taprio_parse_mqprio_opt(dev, mqprio, extack);
+	if (err < 0)
+		return err;
+
+	size = parse_taprio_opt(tb, q, extack);
+	if (size < 0)
+		return size;
+
+	hrtimer_init(&q->advance_timer, q->clockid, HRTIMER_MODE_ABS);
+	q->advance_timer.function = advance_sched;
+
+	switch (q->clockid) {
+	case CLOCK_REALTIME:
+		q->get_time = ktime_get_real;
+		break;
+	case CLOCK_MONOTONIC:
+		q->get_time = ktime_get;
+		break;
+	case CLOCK_BOOTTIME:
+		q->get_time = ktime_get_boottime;
+		break;
+	case CLOCK_TAI:
+		q->get_time = ktime_get_clocktai;
+		break;
+	default:
+		return -ENOTSUPP;
+	}
+
+	for (i = 0; i < dev->real_num_tx_queues; i++) {
+		struct netdev_queue *dev_queue;
+		struct Qdisc *qdisc;
+
+		dev_queue = netdev_get_tx_queue(dev, i);
+		qdisc = qdisc_create_dflt(dev_queue,
+					  &pfifo_qdisc_ops,
+					  TC_H_MAKE(TC_H_MAJ(sch->handle),
+						    TC_H_MIN(i + 1)),
+					  extack);
+		if (!qdisc)
+			return -ENOMEM;
+
+		q->qdiscs[i] = qdisc;
+		qdisc_hash_add(qdisc, true);
+	}
+
+	if (mqprio) {
+		netdev_set_num_tc(dev, mqprio->num_tc);
+		for (i = 0; i < mqprio->num_tc; i++)
+			netdev_set_tc_queue(dev, i,
+					    mqprio->count[i],
+					    mqprio->offset[i]);
+
+		/* Always use supplied priority mappings */
+		for (i = 0; i < TC_BITMASK + 1; i++)
+			netdev_set_prio_tc_map(dev, i,
+					       mqprio->prio_tc_map[i]);
+	}
+
+	if (!__ethtool_get_link_ksettings(dev, &ecmd))
+		link_speed = ecmd.base.speed;
+	else
+		link_speed = SPEED_1000;
+
+	q->picos_per_byte = div64_s64(NSEC_PER_SEC * 1000 * 8,
+				      link_speed * 1000 * 1000);
+
+	expires = taprio_get_first_expires(sch);
+	if (!expires)
+		return 0;
+
+	q->current_expires = expires;
+	q->next_cycle_start = ktime_add_ns(expires, q->cycle_time);
+	hrtimer_start(&q->advance_timer, expires, HRTIMER_MODE_ABS);
+
+	return 0;
+}
+
+static void taprio_destroy(struct Qdisc *sch)
+{
+	struct taprio_sched *q = qdisc_priv(sch);
+	struct net_device *dev = qdisc_dev(sch);
+	struct sched_entry *entry, *n;
+	unsigned int i;
+
+	/* Only cancel hrtimer if it's been initialized. */
+	if (q->clockid != -1)
+		hrtimer_cancel(&q->advance_timer);
+
+	if (q->qdiscs) {
+		for (i = 0; i < dev->num_tx_queues && q->qdiscs[i]; i++)
+			qdisc_destroy(q->qdiscs[i]);
+
+		kfree(q->qdiscs);
+	}
+	q->qdiscs = NULL;
+
+	netdev_set_num_tc(dev, 0);
+
+	list_for_each_entry_safe(entry, n, &q->entries, list) {
+		list_del(&entry->list);
+		kfree(entry);
+	}
+}
+
+static int taprio_init(struct Qdisc *sch, struct nlattr *opt,
+		       struct netlink_ext_ack *extack)
+{
+	struct taprio_sched *q = qdisc_priv(sch);
+	struct net_device *dev = qdisc_dev(sch);
+
+	INIT_LIST_HEAD(&q->entries);
+	RCU_INIT_POINTER(q->current_entry, NULL);
+	spin_lock_init(&q->current_entry_lock);
+	q->root = sch;
+
+	/* We only support static clockids. Use an invalid value as default
+	 * and get the valid one on taprio_change().
+	 */
+	q->clockid = -1;
+
+	if (sch->parent != TC_H_ROOT)
+		return -EOPNOTSUPP;
+
+	if (!netif_is_multiqueue(dev))
+		return -EOPNOTSUPP;
+
+	/* pre-allocate qdisc, attachment can't fail */
+	q->qdiscs = kcalloc(dev->num_tx_queues,
+			    sizeof(q->qdiscs[0]),
+			    GFP_KERNEL);
+
+	if (!q->qdiscs)
+		return -ENOMEM;
+
+	if (!opt)
+		return -EINVAL;
+
+	return taprio_change(sch, opt, extack);
+}
+
+static struct netdev_queue *taprio_queue_get(struct Qdisc *sch,
+					     unsigned long cl)
+{
+	struct net_device *dev = qdisc_dev(sch);
+	unsigned long ntx = cl - 1;
+
+	if (ntx >= dev->num_tx_queues)
+		return NULL;
+
+	return netdev_get_tx_queue(dev, ntx);
+}
+
+static int taprio_graft(struct Qdisc *sch, unsigned long cl,
+			struct Qdisc *new, struct Qdisc **old,
+			struct netlink_ext_ack *extack)
+{
+	struct taprio_sched *q = qdisc_priv(sch);
+	struct net_device *dev = qdisc_dev(sch);
+	struct netdev_queue *dev_queue = taprio_queue_get(sch, cl);
+
+	if (!dev_queue)
+		return -EINVAL;
+
+	if (dev->flags & IFF_UP)
+		dev_deactivate(dev);
+
+	*old = q->qdiscs[cl - 1];
+	q->qdiscs[cl - 1] = new;
+
+	if (new)
+		new->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT;
+
+	if (dev->flags & IFF_UP)
+		dev_activate(dev);
+
+	return 0;
+}
+
+static int dump_entry(struct sk_buff *msg,
+		      const struct sched_entry *entry)
+{
+	struct nlattr *item;
+
+	item = nla_nest_start(msg, TCA_TAPRIO_SCHED_ENTRY);
+	if (!item)
+		return -ENOSPC;
+
+	if (nla_put_u32(msg, TCA_TAPRIO_SCHED_ENTRY_INDEX, entry->index))
+		goto nla_put_failure;
+
+	if (nla_put_u8(msg, TCA_TAPRIO_SCHED_ENTRY_CMD, entry->command))
+		goto nla_put_failure;
+
+	if (nla_put_u32(msg, TCA_TAPRIO_SCHED_ENTRY_GATE_MASK,
+			entry->gate_mask))
+		goto nla_put_failure;
+
+	if (nla_put_u32(msg, TCA_TAPRIO_SCHED_ENTRY_INTERVAL,
+			entry->interval))
+		goto nla_put_failure;
+
+	return nla_nest_end(msg, item);
+
+nla_put_failure:
+	nla_nest_cancel(msg, item);
+	return -1;
+}
+
+static int taprio_dump(struct Qdisc *sch, struct sk_buff *skb)
+{
+	struct taprio_sched *q = qdisc_priv(sch);
+	struct net_device *dev = qdisc_dev(sch);
+	struct tc_mqprio_qopt opt = { 0 };
+	struct nlattr *nest, *entry_list;
+	struct sched_entry *entry;
+	struct Qdisc *qdisc;
+	unsigned int i;
+
+	sch->q.qlen = 0;
+	memset(&sch->bstats, 0, sizeof(sch->bstats));
+	memset(&sch->qstats, 0, sizeof(sch->qstats));
+
+	for (i = 0; i < dev->num_tx_queues; i++) {
+		qdisc = rtnl_dereference(netdev_get_tx_queue(dev, i)->qdisc);
+		spin_lock_bh(qdisc_lock(qdisc));
+		sch->q.qlen		+= qdisc->q.qlen;
+		sch->bstats.bytes	+= qdisc->bstats.bytes;
+		sch->bstats.packets	+= qdisc->bstats.packets;
+		sch->qstats.backlog	+= qdisc->qstats.backlog;
+		sch->qstats.drops	+= qdisc->qstats.drops;
+		sch->qstats.requeues	+= qdisc->qstats.requeues;
+		sch->qstats.overlimits	+= qdisc->qstats.overlimits;
+		spin_unlock_bh(qdisc_lock(qdisc));
+	}
+
+	opt.num_tc = netdev_get_num_tc(dev);
+	memcpy(opt.prio_tc_map, dev->prio_tc_map, sizeof(opt.prio_tc_map));
+
+	for (i = 0; i < netdev_get_num_tc(dev); i++) {
+		opt.count[i] = dev->tc_to_txq[i].count;
+		opt.offset[i] = dev->tc_to_txq[i].offset;
+	}
+
+	nest = nla_nest_start(skb, TCA_OPTIONS);
+	if (!nest)
+		return -ENOSPC;
+
+	if (nla_put(skb, TCA_TAPRIO_ATTR_PRIOMAP, sizeof(opt), &opt))
+		goto options_error;
+
+	if (nla_put_u32(skb, TCA_TAPRIO_ATTR_PREEMPT_MASK, q->preempt_mask))
+		goto options_error;
+
+	if (nla_put_s64(skb, TCA_TAPRIO_ATTR_SCHED_BASE_TIME,
+			q->base_time, TCA_TAPRIO_PAD))
+		goto options_error;
+
+	if (nla_put_s64(skb, TCA_TAPRIO_ATTR_SCHED_CYCLE_TIME,
+			q->cycle_time, TCA_TAPRIO_PAD))
+		goto options_error;
+
+	if (nla_put_s64(skb, TCA_TAPRIO_ATTR_SCHED_EXTENSION_TIME,
+			q->extension_time, TCA_TAPRIO_PAD))
+		goto options_error;
+
+	if (nla_put_s32(skb, TCA_TAPRIO_ATTR_SCHED_CLOCKID, q->clockid))
+		goto options_error;
+
+	entry_list = nla_nest_start(skb, TCA_TAPRIO_ATTR_SCHED_ENTRY_LIST);
+	if (!entry_list)
+		goto options_error;
+
+	list_for_each_entry(entry, &q->entries, list) {
+		if (dump_entry(skb, entry) < 0)
+			goto options_error;
+	}
+
+	nla_nest_end(skb, entry_list);
+
+	return nla_nest_end(skb, nest);
+
+options_error:
+	nla_nest_cancel(skb, nest);
+	return -1;
+}
+
+static struct Qdisc *taprio_leaf(struct Qdisc *sch, unsigned long cl)
+{
+	struct netdev_queue *dev_queue = taprio_queue_get(sch, cl);
+
+	if (!dev_queue)
+		return NULL;
+
+	return dev_queue->qdisc_sleeping;
+}
+
+static unsigned long taprio_find(struct Qdisc *sch, u32 classid)
+{
+	unsigned int ntx = TC_H_MIN(classid);
+
+	if (!taprio_queue_get(sch, ntx))
+		return 0;
+	return ntx;
+}
+
+static int taprio_dump_class(struct Qdisc *sch, unsigned long cl,
+			     struct sk_buff *skb, struct tcmsg *tcm)
+{
+	struct netdev_queue *dev_queue = taprio_queue_get(sch, cl);
+
+	tcm->tcm_parent = TC_H_ROOT;
+	tcm->tcm_handle |= TC_H_MIN(cl);
+	tcm->tcm_info = dev_queue->qdisc_sleeping->handle;
+
+	return 0;
+}
+
+static int taprio_dump_class_stats(struct Qdisc *sch, unsigned long cl,
+				   struct gnet_dump *d)
+	__releases(d->lock)
+	__acquires(d->lock)
+{
+	struct netdev_queue *dev_queue = taprio_queue_get(sch, cl);
+
+	sch = dev_queue->qdisc_sleeping;
+	if (gnet_stats_copy_basic(&sch->running, d, NULL, &sch->bstats) < 0 ||
+	    gnet_stats_copy_queue(d, NULL, &sch->qstats, sch->q.qlen) < 0)
+		return -1;
+	return 0;
+}
+
+static void taprio_walk(struct Qdisc *sch, struct qdisc_walker *arg)
+{
+	struct net_device *dev = qdisc_dev(sch);
+	unsigned long ntx;
+
+	if (arg->stop)
+		return;
+
+	arg->count = arg->skip;
+	for (ntx = arg->skip; ntx < dev->num_tx_queues; ntx++) {
+		if (arg->fn(sch, ntx + 1, arg) < 0) {
+			arg->stop = 1;
+			break;
+		}
+		arg->count++;
+	}
+}
+
+static struct netdev_queue *taprio_select_queue(struct Qdisc *sch,
+						struct tcmsg *tcm)
+{
+	return taprio_queue_get(sch, TC_H_MIN(tcm->tcm_parent));
+}
+
+static const struct Qdisc_class_ops taprio_class_ops = {
+	.graft		= taprio_graft,
+	.leaf		= taprio_leaf,
+	.find		= taprio_find,
+	.walk		= taprio_walk,
+	.dump		= taprio_dump_class,
+	.dump_stats	= taprio_dump_class_stats,
+	.select_queue	= taprio_select_queue,
+};
+
+static struct Qdisc_ops taprio_qdisc_ops __read_mostly = {
+	.cl_ops		= &taprio_class_ops,
+	.id		= "taprio",
+	.priv_size	= sizeof(struct taprio_sched),
+	.init		= taprio_init,
+	.change		= taprio_change,
+	.destroy	= taprio_destroy,
+	.peek		= taprio_peek,
+	.dequeue	= taprio_dequeue,
+	.enqueue	= taprio_enqueue,
+	.dump		= taprio_dump,
+	.owner		= THIS_MODULE,
+};
+
+static int __init taprio_module_init(void)
+{
+	return register_qdisc(&taprio_qdisc_ops);
+}
+
+static void __exit taprio_module_exit(void)
+{
+	unregister_qdisc(&taprio_qdisc_ops);
+}
+
+module_init(taprio_module_init);
+module_exit(taprio_module_exit);
+MODULE_LICENSE("GPL");
-- 
2.18.0

^ permalink raw reply related

* [RFC net-next v1 0/1] net/sched: Introduce the taprio scheduler
From: Vinicius Costa Gomes @ 2018-07-14  0:05 UTC (permalink / raw)
  To: netdev
  Cc: Vinicius Costa Gomes, jesus.sanchez-palencia, tglx, jan.altenberg,
	henrik, richardcochran, levi.pearson, jhs, xiyou.wangcong, jiri


Hi,

This series provides a set of interfaces that can be used by
applications that require (time-based) Scheduled Transmission of
packets. It is comprised by 3 new components to the kernel:

  - etf: the per-queue TxTime-Based scheduling qdisc;
  - taprio: the per-port Time-Aware scheduler qdisc;
  - SO_TXTIME: a socket option + cmsg APIs.

ETF and SO_TXTIME are already applied[1] into the net-next tree. This
is the remaining piece.

Overview
========

The CBS qdisc proposal RFC [2] included some rough ideas about the
design and API of a "taprio" (Time Aware Priority) qdisc. The idea of
presenting the taprio ideas at that point (almost 10 months ago!) was
to show our vision of how things would fit together going forward.
>From that concept stage to this (almost) realised stage the main
differences are:

  - As of now, taprio is a software only implementation of a schedule
    executor;
  - Instead of taprio centralising all the time based decisions, taprio
    can work together with ETF (the Earliest TxTime First), a qdisc
    meant to use the LaunchTime (or similar) feature of various network
    controllers;

In a nutshell, taprio is a root qdisc that can execute a predefined
schedule, etf is a qdisc that provides time based admission control
and "earliest deadline first" dequeue mode, and SO_TXTIME is a socket
option that is used for enabling a socket to be used for time-based
transmission and configuring its parameters.

taprio
======

This scheduler allows the network administrator to configure schedules
for classes of traffic, the configuration interface is similar to what
IEEE 802.1Qbv-2015 defines.

Example configuration:

$ tc qdisc add dev enp2s0 parent root handle 100 taprio \
	    num_tc 3 \
	    map 2 2 1 0 2 2 2 2 2 2 2 2 2 2 2 2 \
	    queues 1@0 1@1 2@2 \
	    sched-file ~/gates.sched \
	    base-time 1528743495910289987 \
	    clockid CLOCK_TAI

This qdisc borrows a few concepts from mqprio and so, most the
parameters are similar to mqprio. The main difference is the
'sched-file' parameter, one example on a schedule file would be:

gates.sched
-----------
S 01 300000
S 02 300000
S 04 300000

The format of each line is:
<CMD> <GATE MASK> <INTERVAL>

The only supported <CMD> is "S", which means "SetGateStates",
following the IEEE 802.1Qbv-2015 definition (Table 8-6). <GATE MASK>
is a bitmask where each bit is a associated with a traffic class, so
bit 0 (the least significant bit) being "on" means that traffic class
0 is "active" for that schedule entry. <INTERVAL> is a time duration
in nanoseconds that specifies for how long that state defined by <CMD>
and <GATE MASK> should be held before moving to the next entry.

This schedule is circular, that is, after the last entry is executed
it starts from the first one, indefinitely.

The other parameters can be defined as follows:
  - base-time: allows that multiple systems can have synchronised
    schedules, it specifies the instant when the schedule starts;
  - clockid: specifies the reference clock to be used;

A more complete example can be found here, with instructions of how to
test it:

https://gist.github.com/jeez/bd3afeff081ba64a695008dd8215866f [3]

The basic design of the scheduler is simple, after we calculate the
first expiration of the hrtimer, we set the next expiration to be the
previous plus the current entry's interval. At each time the function
runs, we set the current_entry, which has a gate_mask (that controls
which traffic classes are allowed to "go out" during each interval),
and we reuse this callback to "kick" the qdisc (this is the reason
that the usual qdisc watchdog isn't used).


Known Issues
============

 - As taprio is a software only implementation, and there's another
   layer of queuing in the network controller, packets can still
   leave the controller outside their "correct" windows. This happens
   mostly for low-priority classes, and is more evident if they are
   'starved' by the higher priority ones;
 - There's no support for changing the schedule during runtime;

This series is also hosted on github and can be found at [4].
The companion iproute2 patches can be found at [5].


Cheers,

^ permalink raw reply

* Re: [bpf-next,v3,11/13] tools: bpf: make use of reallocarray
From: Guenter Roeck @ 2018-07-13 23:53 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: alexei.starovoitov, daniel, Andrey Ignatov, oss-drivers, netdev
In-Reply-To: <20180710214307.4834-12-jakub.kicinski@netronome.com>

Hi,

On Tue, Jul 10, 2018 at 02:43:05PM -0700, Jakub Kicinski wrote:
> reallocarray() is a safer variant of realloc which checks for
> multiplication overflow in case of array allocation.  Since it's
> not available in Glibc < 2.26 import kernel's overflow.h and
> add a static inline implementation when needed.  Use feature
> detection to probe for existence of reallocarray.
> 

This probe doesn't work on my system (Ubuntu 16.04).

libbpf.c: In function ‘bpf_object__add_program’:
libbpf.c:326:10: error: implicit declaration of function ‘reallocarray’

bisect points to this patch.

Guenter

^ permalink raw reply

* editing for your images
From: Simon @ 2018-07-13 11:38 UTC (permalink / raw)
  To: netdev

We are a team, we can process 300+ images per day for you.

If you need any image editing, please let us know.

Photos cut out;
Photos clipping path;
Photos masking;
Photo shadow creation;
Photos retouching;
Beauty Model retouching on skin, face, body;
Glamour retouching;
Products retouching.

We can give you editing test on your photos.

Turnaround time fast
7/24/365 available

Thanks,
Simon

^ permalink raw reply

* editing for your images
From: Simon @ 2018-07-13 12:12 UTC (permalink / raw)
  To: netdev

We are a team, we can process 300+ images per day for you.

If you need any image editing, please let us know.

Photos cut out;
Photos clipping path;
Photos masking;
Photo shadow creation;
Photos retouching;
Beauty Model retouching on skin, face, body;
Glamour retouching;
Products retouching.

We can give you editing test on your photos.

Turnaround time fast
7/24/365 available

Thanks,
Simon

^ permalink raw reply

* Re: [PATCH v3 net-next 3/3] rds: Extend RDS API for IPv6 support
From: Santosh Shilimkar @ 2018-07-13 23:31 UTC (permalink / raw)
  To: David Miller; +Cc: ka-cheong.poon, netdev, sowmini.varadhan, rds-devel
In-Reply-To: <20180713.162703.1175465436358158939.davem@davemloft.net>

On 7/13/2018 4:27 PM, David Miller wrote:
> From: Santosh Shilimkar <santosh.shilimkar@oracle.com>
> Date: Fri, 13 Jul 2018 15:00:59 -0700
> 
>> Ofcourse any application built using upstream header and
>> using SO_RDS_TRANSPORT will break but since this particular
>> option was added for special case(application wants to
>> upfront select transport instead letting bind figure it out),
>> our hope its not used by other application(s).
> 
> We can't let people have different UAPIs from upstream on a whim like
> this then change the already released upstream UAPI to match.
> 
> Please take this into consideration when making changes in the future.
>
Will not be repeated in future.

> I'm not allowing this upstream UAPI break, sorry.
> 
Ok Dave !!

Regards,
Santosh

^ permalink raw reply

* Re: [PATCH v3 net-next 3/3] rds: Extend RDS API for IPv6 support
From: David Miller @ 2018-07-13 23:27 UTC (permalink / raw)
  To: santosh.shilimkar; +Cc: ka-cheong.poon, netdev, sowmini.varadhan, rds-devel
In-Reply-To: <da7e76c6-1b52-08d2-b960-ec6067df3fca@oracle.com>

From: Santosh Shilimkar <santosh.shilimkar@oracle.com>
Date: Fri, 13 Jul 2018 15:00:59 -0700

> Ofcourse any application built using upstream header and
> using SO_RDS_TRANSPORT will break but since this particular
> option was added for special case(application wants to
> upfront select transport instead letting bind figure it out),
> our hope its not used by other application(s).

We can't let people have different UAPIs from upstream on a whim like
this then change the already released upstream UAPI to match.

Please take this into consideration when making changes in the future.

I'm not allowing this upstream UAPI break, sorry.

^ permalink raw reply

* Re: [PATCH v2 nf-next 1/2] ipv6: remove dependency of nf_defrag_ipv6 on ipv6 module
From: kbuild test robot @ 2018-07-13 23:14 UTC (permalink / raw)
  To: Florian Westphal; +Cc: kbuild-all, netfilter-devel, netdev, Florian Westphal
In-Reply-To: <20180713142754.23349-1-fw@strlen.de>

[-- Attachment #1: Type: text/plain, Size: 37593 bytes --]

Hi Florian,

I love your patch! Yet something to improve:

[auto build test ERROR on nf-next/master]

url:    https://github.com/0day-ci/linux/commits/Florian-Westphal/ipv6-remove-dependency-of-nf_defrag_ipv6-on-ipv6-module/20180714-051523
base:   https://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next.git master
config: x86_64-randconfig-u0-07140609 (attached as .config)
compiler: gcc-5 (Debian 5.5.0-3) 5.4.1 20171010
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All errors (new ones prefixed by >>):

   In file included from include/asm-generic/percpu.h:7:0,
                    from arch/x86/include/asm/percpu.h:543,
                    from arch/x86/include/asm/preempt.h:6,
                    from include/linux/preempt.h:81,
                    from include/linux/spinlock.h:51,
                    from include/linux/seqlock.h:36,
                    from include/linux/time.h:6,
                    from include/linux/stat.h:19,
                    from include/linux/module.h:10,
                    from net//openvswitch/conntrack.c:14:
   include/net/ipv6_frag.h: In function 'ip6frag_expire_frag_queue':
>> include/net/ipv6.h:171:34: error: 'struct netns_mib' has no member named 'ipv6_statistics'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
                                     ^
   include/linux/percpu-defs.h:221:47: note: in definition of macro '__verify_pcpu_ptr'
     const void __percpu *__vpp_verify = (typeof((ptr) + 0))NULL; \
                                                  ^
   include/linux/percpu-defs.h:424:32: note: in expansion of macro '__pcpu_size_call'
    #define raw_cpu_add(pcp, val)  __pcpu_size_call(raw_cpu_add_, pcp, val)
                                   ^
   include/linux/percpu-defs.h:460:2: note: in expansion of macro 'raw_cpu_add'
     raw_cpu_add(pcp, val);      \
     ^
   include/linux/percpu-defs.h:499:30: note: in expansion of macro '__this_cpu_add'
    #define __this_cpu_inc(pcp)  __this_cpu_add(pcp, 1)
                                 ^
   include/net/snmp.h:127:4: note: in expansion of macro '__this_cpu_inc'
       __this_cpu_inc(mib->mibs[field])
       ^
   include/net/snmp.h:192:41: note: in expansion of macro '__SNMP_INC_STATS'
    #define __SNMP_INC_STATS64(mib, field)  __SNMP_INC_STATS(mib, field)
                                            ^
   include/net/ipv6.h:171:2: note: in expansion of macro '__SNMP_INC_STATS64'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
     ^
   include/net/ipv6.h:213:3: note: in expansion of macro '_DEVINC'
      _DEVINC(net, ipv6, __, idev, field)
      ^
   include/net/ipv6_frag.h:80:2: note: in expansion of macro '__IP6_INC_STATS'
     __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
     ^
>> include/net/ipv6.h:171:34: error: 'struct netns_mib' has no member named 'ipv6_statistics'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
                                     ^
   include/linux/percpu-defs.h:378:16: note: in definition of macro '__pcpu_size_call'
     switch(sizeof(variable)) {     \
                   ^
   include/linux/percpu-defs.h:460:2: note: in expansion of macro 'raw_cpu_add'
     raw_cpu_add(pcp, val);      \
     ^
   include/linux/percpu-defs.h:499:30: note: in expansion of macro '__this_cpu_add'
    #define __this_cpu_inc(pcp)  __this_cpu_add(pcp, 1)
                                 ^
   include/net/snmp.h:127:4: note: in expansion of macro '__this_cpu_inc'
       __this_cpu_inc(mib->mibs[field])
       ^
   include/net/snmp.h:192:41: note: in expansion of macro '__SNMP_INC_STATS'
    #define __SNMP_INC_STATS64(mib, field)  __SNMP_INC_STATS(mib, field)
                                            ^
   include/net/ipv6.h:171:2: note: in expansion of macro '__SNMP_INC_STATS64'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
     ^
   include/net/ipv6.h:213:3: note: in expansion of macro '_DEVINC'
      _DEVINC(net, ipv6, __, idev, field)
      ^
   include/net/ipv6_frag.h:80:2: note: in expansion of macro '__IP6_INC_STATS'
     __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
     ^
   In file included from arch/x86/include/asm/preempt.h:6:0,
                    from include/linux/preempt.h:81,
                    from include/linux/spinlock.h:51,
                    from include/linux/seqlock.h:36,
                    from include/linux/time.h:6,
                    from include/linux/stat.h:19,
                    from include/linux/module.h:10,
                    from net//openvswitch/conntrack.c:14:
>> include/net/ipv6.h:171:34: error: 'struct netns_mib' has no member named 'ipv6_statistics'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
                                     ^
   arch/x86/include/asm/percpu.h:129:17: note: in definition of macro 'percpu_add_op'
     typedef typeof(var) pao_T__;     \
                    ^
   include/linux/percpu-defs.h:379:11: note: in expansion of macro 'raw_cpu_add_1'
      case 1: stem##1(variable, __VA_ARGS__);break;  \
              ^
   include/linux/percpu-defs.h:424:32: note: in expansion of macro '__pcpu_size_call'
    #define raw_cpu_add(pcp, val)  __pcpu_size_call(raw_cpu_add_, pcp, val)
                                   ^
   include/linux/percpu-defs.h:460:2: note: in expansion of macro 'raw_cpu_add'
     raw_cpu_add(pcp, val);      \
     ^
   include/linux/percpu-defs.h:499:30: note: in expansion of macro '__this_cpu_add'
    #define __this_cpu_inc(pcp)  __this_cpu_add(pcp, 1)
                                 ^
   include/net/snmp.h:127:4: note: in expansion of macro '__this_cpu_inc'
       __this_cpu_inc(mib->mibs[field])
       ^
   include/net/snmp.h:192:41: note: in expansion of macro '__SNMP_INC_STATS'
    #define __SNMP_INC_STATS64(mib, field)  __SNMP_INC_STATS(mib, field)
                                            ^
   include/net/ipv6.h:171:2: note: in expansion of macro '__SNMP_INC_STATS64'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
     ^
   include/net/ipv6.h:213:3: note: in expansion of macro '_DEVINC'
      _DEVINC(net, ipv6, __, idev, field)
      ^
   include/net/ipv6_frag.h:80:2: note: in expansion of macro '__IP6_INC_STATS'
     __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
     ^
>> include/net/ipv6.h:171:34: error: 'struct netns_mib' has no member named 'ipv6_statistics'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
                                     ^
   arch/x86/include/asm/percpu.h:138:17: note: in definition of macro 'percpu_add_op'
     switch (sizeof(var)) {      \
                    ^
   include/linux/percpu-defs.h:379:11: note: in expansion of macro 'raw_cpu_add_1'
      case 1: stem##1(variable, __VA_ARGS__);break;  \
              ^
   include/linux/percpu-defs.h:424:32: note: in expansion of macro '__pcpu_size_call'
    #define raw_cpu_add(pcp, val)  __pcpu_size_call(raw_cpu_add_, pcp, val)
                                   ^
   include/linux/percpu-defs.h:460:2: note: in expansion of macro 'raw_cpu_add'
     raw_cpu_add(pcp, val);      \
     ^
   include/linux/percpu-defs.h:499:30: note: in expansion of macro '__this_cpu_add'
    #define __this_cpu_inc(pcp)  __this_cpu_add(pcp, 1)
                                 ^
   include/net/snmp.h:127:4: note: in expansion of macro '__this_cpu_inc'
       __this_cpu_inc(mib->mibs[field])
       ^
   include/net/snmp.h:192:41: note: in expansion of macro '__SNMP_INC_STATS'
    #define __SNMP_INC_STATS64(mib, field)  __SNMP_INC_STATS(mib, field)
                                            ^
   include/net/ipv6.h:171:2: note: in expansion of macro '__SNMP_INC_STATS64'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
     ^
   include/net/ipv6.h:213:3: note: in expansion of macro '_DEVINC'
      _DEVINC(net, ipv6, __, idev, field)
      ^
   include/net/ipv6_frag.h:80:2: note: in expansion of macro '__IP6_INC_STATS'
     __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
     ^
>> include/net/ipv6.h:171:34: error: 'struct netns_mib' has no member named 'ipv6_statistics'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
                                     ^
   arch/x86/include/asm/percpu.h:141:39: note: in definition of macro 'percpu_add_op'
       asm("incb "__percpu_arg(0) : "+m" (var)); \
                                          ^
   include/linux/percpu-defs.h:379:11: note: in expansion of macro 'raw_cpu_add_1'
      case 1: stem##1(variable, __VA_ARGS__);break;  \
              ^
   include/linux/percpu-defs.h:424:32: note: in expansion of macro '__pcpu_size_call'
    #define raw_cpu_add(pcp, val)  __pcpu_size_call(raw_cpu_add_, pcp, val)
                                   ^
   include/linux/percpu-defs.h:460:2: note: in expansion of macro 'raw_cpu_add'
     raw_cpu_add(pcp, val);      \
     ^
   include/linux/percpu-defs.h:499:30: note: in expansion of macro '__this_cpu_add'
    #define __this_cpu_inc(pcp)  __this_cpu_add(pcp, 1)
                                 ^
   include/net/snmp.h:127:4: note: in expansion of macro '__this_cpu_inc'
       __this_cpu_inc(mib->mibs[field])
       ^
   include/net/snmp.h:192:41: note: in expansion of macro '__SNMP_INC_STATS'
    #define __SNMP_INC_STATS64(mib, field)  __SNMP_INC_STATS(mib, field)
                                            ^
   include/net/ipv6.h:171:2: note: in expansion of macro '__SNMP_INC_STATS64'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
     ^
   include/net/ipv6.h:213:3: note: in expansion of macro '_DEVINC'
      _DEVINC(net, ipv6, __, idev, field)
      ^
   include/net/ipv6_frag.h:80:2: note: in expansion of macro '__IP6_INC_STATS'
     __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
     ^
>> include/net/ipv6.h:171:34: error: 'struct netns_mib' has no member named 'ipv6_statistics'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
                                     ^
   arch/x86/include/asm/percpu.h:143:39: note: in definition of macro 'percpu_add_op'
       asm("decb "__percpu_arg(0) : "+m" (var)); \
                                          ^
   include/linux/percpu-defs.h:379:11: note: in expansion of macro 'raw_cpu_add_1'
      case 1: stem##1(variable, __VA_ARGS__);break;  \
              ^
   include/linux/percpu-defs.h:424:32: note: in expansion of macro '__pcpu_size_call'
    #define raw_cpu_add(pcp, val)  __pcpu_size_call(raw_cpu_add_, pcp, val)
                                   ^
   include/linux/percpu-defs.h:460:2: note: in expansion of macro 'raw_cpu_add'
     raw_cpu_add(pcp, val);      \
     ^
   include/linux/percpu-defs.h:499:30: note: in expansion of macro '__this_cpu_add'
    #define __this_cpu_inc(pcp)  __this_cpu_add(pcp, 1)
                                 ^
   include/net/snmp.h:127:4: note: in expansion of macro '__this_cpu_inc'
       __this_cpu_inc(mib->mibs[field])
       ^
   include/net/snmp.h:192:41: note: in expansion of macro '__SNMP_INC_STATS'
    #define __SNMP_INC_STATS64(mib, field)  __SNMP_INC_STATS(mib, field)
                                            ^
   include/net/ipv6.h:171:2: note: in expansion of macro '__SNMP_INC_STATS64'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
     ^
   include/net/ipv6.h:213:3: note: in expansion of macro '_DEVINC'
      _DEVINC(net, ipv6, __, idev, field)
      ^
   include/net/ipv6_frag.h:80:2: note: in expansion of macro '__IP6_INC_STATS'
     __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
     ^
>> include/net/ipv6.h:171:34: error: 'struct netns_mib' has no member named 'ipv6_statistics'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
                                     ^
   arch/x86/include/asm/percpu.h:146:16: note: in definition of macro 'percpu_add_op'
           : "+m" (var)    \
                   ^
   include/linux/percpu-defs.h:379:11: note: in expansion of macro 'raw_cpu_add_1'
      case 1: stem##1(variable, __VA_ARGS__);break;  \
              ^
   include/linux/percpu-defs.h:424:32: note: in expansion of macro '__pcpu_size_call'
    #define raw_cpu_add(pcp, val)  __pcpu_size_call(raw_cpu_add_, pcp, val)
                                   ^
   include/linux/percpu-defs.h:460:2: note: in expansion of macro 'raw_cpu_add'
     raw_cpu_add(pcp, val);      \
     ^
   include/linux/percpu-defs.h:499:30: note: in expansion of macro '__this_cpu_add'
    #define __this_cpu_inc(pcp)  __this_cpu_add(pcp, 1)
                                 ^
   include/net/snmp.h:127:4: note: in expansion of macro '__this_cpu_inc'
       __this_cpu_inc(mib->mibs[field])
       ^
   include/net/snmp.h:192:41: note: in expansion of macro '__SNMP_INC_STATS'
    #define __SNMP_INC_STATS64(mib, field)  __SNMP_INC_STATS(mib, field)
                                            ^
   include/net/ipv6.h:171:2: note: in expansion of macro '__SNMP_INC_STATS64'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
     ^
   include/net/ipv6.h:213:3: note: in expansion of macro '_DEVINC'
      _DEVINC(net, ipv6, __, idev, field)
      ^
   include/net/ipv6_frag.h:80:2: note: in expansion of macro '__IP6_INC_STATS'
     __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
     ^
>> include/net/ipv6.h:171:34: error: 'struct netns_mib' has no member named 'ipv6_statistics'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
                                     ^
   arch/x86/include/asm/percpu.h:151:39: note: in definition of macro 'percpu_add_op'
       asm("incw "__percpu_arg(0) : "+m" (var)); \
                                          ^
   include/linux/percpu-defs.h:379:11: note: in expansion of macro 'raw_cpu_add_1'
      case 1: stem##1(variable, __VA_ARGS__);break;  \
              ^
   include/linux/percpu-defs.h:424:32: note: in expansion of macro '__pcpu_size_call'
    #define raw_cpu_add(pcp, val)  __pcpu_size_call(raw_cpu_add_, pcp, val)
                                   ^
   include/linux/percpu-defs.h:460:2: note: in expansion of macro 'raw_cpu_add'
     raw_cpu_add(pcp, val);      \
     ^
   include/linux/percpu-defs.h:499:30: note: in expansion of macro '__this_cpu_add'
    #define __this_cpu_inc(pcp)  __this_cpu_add(pcp, 1)
                                 ^
   include/net/snmp.h:127:4: note: in expansion of macro '__this_cpu_inc'
       __this_cpu_inc(mib->mibs[field])
       ^
   include/net/snmp.h:192:41: note: in expansion of macro '__SNMP_INC_STATS'
    #define __SNMP_INC_STATS64(mib, field)  __SNMP_INC_STATS(mib, field)
                                            ^
   include/net/ipv6.h:171:2: note: in expansion of macro '__SNMP_INC_STATS64'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
     ^
   include/net/ipv6.h:213:3: note: in expansion of macro '_DEVINC'
      _DEVINC(net, ipv6, __, idev, field)
      ^
   include/net/ipv6_frag.h:80:2: note: in expansion of macro '__IP6_INC_STATS'
     __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
     ^
>> include/net/ipv6.h:171:34: error: 'struct netns_mib' has no member named 'ipv6_statistics'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
                                     ^
   arch/x86/include/asm/percpu.h:153:39: note: in definition of macro 'percpu_add_op'
       asm("decw "__percpu_arg(0) : "+m" (var)); \
                                          ^
   include/linux/percpu-defs.h:379:11: note: in expansion of macro 'raw_cpu_add_1'
      case 1: stem##1(variable, __VA_ARGS__);break;  \
              ^
   include/linux/percpu-defs.h:424:32: note: in expansion of macro '__pcpu_size_call'
    #define raw_cpu_add(pcp, val)  __pcpu_size_call(raw_cpu_add_, pcp, val)
                                   ^
   include/linux/percpu-defs.h:460:2: note: in expansion of macro 'raw_cpu_add'
     raw_cpu_add(pcp, val);      \
     ^
   include/linux/percpu-defs.h:499:30: note: in expansion of macro '__this_cpu_add'
    #define __this_cpu_inc(pcp)  __this_cpu_add(pcp, 1)
                                 ^
   include/net/snmp.h:127:4: note: in expansion of macro '__this_cpu_inc'
       __this_cpu_inc(mib->mibs[field])
       ^
   include/net/snmp.h:192:41: note: in expansion of macro '__SNMP_INC_STATS'
    #define __SNMP_INC_STATS64(mib, field)  __SNMP_INC_STATS(mib, field)
                                            ^
   include/net/ipv6.h:171:2: note: in expansion of macro '__SNMP_INC_STATS64'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
     ^
   include/net/ipv6.h:213:3: note: in expansion of macro '_DEVINC'
      _DEVINC(net, ipv6, __, idev, field)
      ^
   include/net/ipv6_frag.h:80:2: note: in expansion of macro '__IP6_INC_STATS'
     __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
     ^
>> include/net/ipv6.h:171:34: error: 'struct netns_mib' has no member named 'ipv6_statistics'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
                                     ^
   arch/x86/include/asm/percpu.h:156:16: note: in definition of macro 'percpu_add_op'
           : "+m" (var)    \
                   ^
   include/linux/percpu-defs.h:379:11: note: in expansion of macro 'raw_cpu_add_1'
      case 1: stem##1(variable, __VA_ARGS__);break;  \
              ^
   include/linux/percpu-defs.h:424:32: note: in expansion of macro '__pcpu_size_call'
    #define raw_cpu_add(pcp, val)  __pcpu_size_call(raw_cpu_add_, pcp, val)
                                   ^
   include/linux/percpu-defs.h:460:2: note: in expansion of macro 'raw_cpu_add'
     raw_cpu_add(pcp, val);      \
     ^
   include/linux/percpu-defs.h:499:30: note: in expansion of macro '__this_cpu_add'
    #define __this_cpu_inc(pcp)  __this_cpu_add(pcp, 1)
                                 ^
   include/net/snmp.h:127:4: note: in expansion of macro '__this_cpu_inc'
       __this_cpu_inc(mib->mibs[field])
       ^
   include/net/snmp.h:192:41: note: in expansion of macro '__SNMP_INC_STATS'
    #define __SNMP_INC_STATS64(mib, field)  __SNMP_INC_STATS(mib, field)
                                            ^
   include/net/ipv6.h:171:2: note: in expansion of macro '__SNMP_INC_STATS64'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
     ^
   include/net/ipv6.h:213:3: note: in expansion of macro '_DEVINC'
      _DEVINC(net, ipv6, __, idev, field)
      ^
   include/net/ipv6_frag.h:80:2: note: in expansion of macro '__IP6_INC_STATS'
     __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
     ^
>> include/net/ipv6.h:171:34: error: 'struct netns_mib' has no member named 'ipv6_statistics'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
                                     ^
   arch/x86/include/asm/percpu.h:161:39: note: in definition of macro 'percpu_add_op'
       asm("incl "__percpu_arg(0) : "+m" (var)); \
                                          ^
   include/linux/percpu-defs.h:379:11: note: in expansion of macro 'raw_cpu_add_1'
      case 1: stem##1(variable, __VA_ARGS__);break;  \
              ^
   include/linux/percpu-defs.h:424:32: note: in expansion of macro '__pcpu_size_call'
    #define raw_cpu_add(pcp, val)  __pcpu_size_call(raw_cpu_add_, pcp, val)
                                   ^
   include/linux/percpu-defs.h:460:2: note: in expansion of macro 'raw_cpu_add'
     raw_cpu_add(pcp, val);      \
     ^
   include/linux/percpu-defs.h:499:30: note: in expansion of macro '__this_cpu_add'
    #define __this_cpu_inc(pcp)  __this_cpu_add(pcp, 1)
                                 ^
   include/net/snmp.h:127:4: note: in expansion of macro '__this_cpu_inc'
       __this_cpu_inc(mib->mibs[field])
       ^
   include/net/snmp.h:192:41: note: in expansion of macro '__SNMP_INC_STATS'
    #define __SNMP_INC_STATS64(mib, field)  __SNMP_INC_STATS(mib, field)
                                            ^
   include/net/ipv6.h:171:2: note: in expansion of macro '__SNMP_INC_STATS64'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
     ^
   include/net/ipv6.h:213:3: note: in expansion of macro '_DEVINC'
      _DEVINC(net, ipv6, __, idev, field)
      ^
   include/net/ipv6_frag.h:80:2: note: in expansion of macro '__IP6_INC_STATS'
     __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
     ^
>> include/net/ipv6.h:171:34: error: 'struct netns_mib' has no member named 'ipv6_statistics'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
                                     ^
   arch/x86/include/asm/percpu.h:163:39: note: in definition of macro 'percpu_add_op'
       asm("decl "__percpu_arg(0) : "+m" (var)); \
                                          ^
   include/linux/percpu-defs.h:379:11: note: in expansion of macro 'raw_cpu_add_1'
      case 1: stem##1(variable, __VA_ARGS__);break;  \
              ^
   include/linux/percpu-defs.h:424:32: note: in expansion of macro '__pcpu_size_call'
    #define raw_cpu_add(pcp, val)  __pcpu_size_call(raw_cpu_add_, pcp, val)
                                   ^
   include/linux/percpu-defs.h:460:2: note: in expansion of macro 'raw_cpu_add'
     raw_cpu_add(pcp, val);      \
     ^
   include/linux/percpu-defs.h:499:30: note: in expansion of macro '__this_cpu_add'
    #define __this_cpu_inc(pcp)  __this_cpu_add(pcp, 1)
                                 ^
   include/net/snmp.h:127:4: note: in expansion of macro '__this_cpu_inc'
       __this_cpu_inc(mib->mibs[field])
       ^
   include/net/snmp.h:192:41: note: in expansion of macro '__SNMP_INC_STATS'
    #define __SNMP_INC_STATS64(mib, field)  __SNMP_INC_STATS(mib, field)
                                            ^
   include/net/ipv6.h:171:2: note: in expansion of macro '__SNMP_INC_STATS64'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
     ^
   include/net/ipv6.h:213:3: note: in expansion of macro '_DEVINC'
      _DEVINC(net, ipv6, __, idev, field)
      ^
   include/net/ipv6_frag.h:80:2: note: in expansion of macro '__IP6_INC_STATS'
     __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
     ^
>> include/net/ipv6.h:171:34: error: 'struct netns_mib' has no member named 'ipv6_statistics'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
                                     ^
   arch/x86/include/asm/percpu.h:166:16: note: in definition of macro 'percpu_add_op'
           : "+m" (var)    \
                   ^
   include/linux/percpu-defs.h:379:11: note: in expansion of macro 'raw_cpu_add_1'
      case 1: stem##1(variable, __VA_ARGS__);break;  \
              ^
   include/linux/percpu-defs.h:424:32: note: in expansion of macro '__pcpu_size_call'
    #define raw_cpu_add(pcp, val)  __pcpu_size_call(raw_cpu_add_, pcp, val)
                                   ^
   include/linux/percpu-defs.h:460:2: note: in expansion of macro 'raw_cpu_add'
     raw_cpu_add(pcp, val);      \
     ^
   include/linux/percpu-defs.h:499:30: note: in expansion of macro '__this_cpu_add'
    #define __this_cpu_inc(pcp)  __this_cpu_add(pcp, 1)
                                 ^
   include/net/snmp.h:127:4: note: in expansion of macro '__this_cpu_inc'
       __this_cpu_inc(mib->mibs[field])
       ^
   include/net/snmp.h:192:41: note: in expansion of macro '__SNMP_INC_STATS'
    #define __SNMP_INC_STATS64(mib, field)  __SNMP_INC_STATS(mib, field)
                                            ^
   include/net/ipv6.h:171:2: note: in expansion of macro '__SNMP_INC_STATS64'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
     ^
   include/net/ipv6.h:213:3: note: in expansion of macro '_DEVINC'
      _DEVINC(net, ipv6, __, idev, field)
      ^
   include/net/ipv6_frag.h:80:2: note: in expansion of macro '__IP6_INC_STATS'
     __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
     ^
>> include/net/ipv6.h:171:34: error: 'struct netns_mib' has no member named 'ipv6_statistics'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
                                     ^
   arch/x86/include/asm/percpu.h:401:34: note: in expansion of macro 'percpu_add_op'
    #define raw_cpu_add_1(pcp, val)  percpu_add_op((pcp), val)
                                     ^
   include/linux/percpu-defs.h:379:11: note: in expansion of macro 'raw_cpu_add_1'
      case 1: stem##1(variable, __VA_ARGS__);break;  \
              ^
   include/linux/percpu-defs.h:424:32: note: in expansion of macro '__pcpu_size_call'
    #define raw_cpu_add(pcp, val)  __pcpu_size_call(raw_cpu_add_, pcp, val)
                                   ^
   include/linux/percpu-defs.h:460:2: note: in expansion of macro 'raw_cpu_add'
     raw_cpu_add(pcp, val);      \
     ^
   include/linux/percpu-defs.h:499:30: note: in expansion of macro '__this_cpu_add'
    #define __this_cpu_inc(pcp)  __this_cpu_add(pcp, 1)
                                 ^
   include/net/snmp.h:127:4: note: in expansion of macro '__this_cpu_inc'
       __this_cpu_inc(mib->mibs[field])
       ^
   include/net/snmp.h:192:41: note: in expansion of macro '__SNMP_INC_STATS'
    #define __SNMP_INC_STATS64(mib, field)  __SNMP_INC_STATS(mib, field)
                                            ^
   include/net/ipv6.h:171:2: note: in expansion of macro '__SNMP_INC_STATS64'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
     ^
   include/net/ipv6.h:213:3: note: in expansion of macro '_DEVINC'
      _DEVINC(net, ipv6, __, idev, field)
      ^
   include/net/ipv6_frag.h:80:2: note: in expansion of macro '__IP6_INC_STATS'
     __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
     ^
>> include/net/ipv6.h:171:34: error: 'struct netns_mib' has no member named 'ipv6_statistics'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
                                     ^
   arch/x86/include/asm/percpu.h:173:39: note: in definition of macro 'percpu_add_op'
       asm("decq "__percpu_arg(0) : "+m" (var)); \
                                          ^
   include/linux/percpu-defs.h:379:11: note: in expansion of macro 'raw_cpu_add_1'
      case 1: stem##1(variable, __VA_ARGS__);break;  \
              ^
   include/linux/percpu-defs.h:424:32: note: in expansion of macro '__pcpu_size_call'
    #define raw_cpu_add(pcp, val)  __pcpu_size_call(raw_cpu_add_, pcp, val)
                                   ^
   include/linux/percpu-defs.h:460:2: note: in expansion of macro 'raw_cpu_add'
     raw_cpu_add(pcp, val);      \
     ^
   include/linux/percpu-defs.h:499:30: note: in expansion of macro '__this_cpu_add'
    #define __this_cpu_inc(pcp)  __this_cpu_add(pcp, 1)
                                 ^
   include/net/snmp.h:127:4: note: in expansion of macro '__this_cpu_inc'
       __this_cpu_inc(mib->mibs[field])
       ^
   include/net/snmp.h:192:41: note: in expansion of macro '__SNMP_INC_STATS'
    #define __SNMP_INC_STATS64(mib, field)  __SNMP_INC_STATS(mib, field)
                                            ^
   include/net/ipv6.h:171:2: note: in expansion of macro '__SNMP_INC_STATS64'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
     ^
   include/net/ipv6.h:213:3: note: in expansion of macro '_DEVINC'
      _DEVINC(net, ipv6, __, idev, field)
      ^
   include/net/ipv6_frag.h:80:2: note: in expansion of macro '__IP6_INC_STATS'
     __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
     ^
>> include/net/ipv6.h:171:34: error: 'struct netns_mib' has no member named 'ipv6_statistics'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
                                     ^
   arch/x86/include/asm/percpu.h:176:16: note: in definition of macro 'percpu_add_op'
           : "+m" (var)    \
                   ^
   include/linux/percpu-defs.h:379:11: note: in expansion of macro 'raw_cpu_add_1'
      case 1: stem##1(variable, __VA_ARGS__);break;  \
              ^
   include/linux/percpu-defs.h:424:32: note: in expansion of macro '__pcpu_size_call'
    #define raw_cpu_add(pcp, val)  __pcpu_size_call(raw_cpu_add_, pcp, val)
                                   ^
   include/linux/percpu-defs.h:460:2: note: in expansion of macro 'raw_cpu_add'
     raw_cpu_add(pcp, val);      \
     ^
   include/linux/percpu-defs.h:499:30: note: in expansion of macro '__this_cpu_add'
    #define __this_cpu_inc(pcp)  __this_cpu_add(pcp, 1)
                                 ^
   include/net/snmp.h:127:4: note: in expansion of macro '__this_cpu_inc'
       __this_cpu_inc(mib->mibs[field])
       ^
   include/net/snmp.h:192:41: note: in expansion of macro '__SNMP_INC_STATS'
    #define __SNMP_INC_STATS64(mib, field)  __SNMP_INC_STATS(mib, field)
                                            ^
   include/net/ipv6.h:171:2: note: in expansion of macro '__SNMP_INC_STATS64'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
     ^
   include/net/ipv6.h:213:3: note: in expansion of macro '_DEVINC'
      _DEVINC(net, ipv6, __, idev, field)
      ^
   include/net/ipv6_frag.h:80:2: note: in expansion of macro '__IP6_INC_STATS'
     __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
     ^
>> include/net/ipv6.h:171:34: error: 'struct netns_mib' has no member named 'ipv6_statistics'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
                                     ^
   arch/x86/include/asm/percpu.h:129:17: note: in definition of macro 'percpu_add_op'
     typedef typeof(var) pao_T__;     \
                    ^
   include/linux/percpu-defs.h:380:11: note: in expansion of macro 'raw_cpu_add_2'
      case 2: stem##2(variable, __VA_ARGS__);break;  \
              ^
   include/linux/percpu-defs.h:424:32: note: in expansion of macro '__pcpu_size_call'
    #define raw_cpu_add(pcp, val)  __pcpu_size_call(raw_cpu_add_, pcp, val)
                                   ^
   include/linux/percpu-defs.h:460:2: note: in expansion of macro 'raw_cpu_add'
     raw_cpu_add(pcp, val);      \
     ^
   include/linux/percpu-defs.h:499:30: note: in expansion of macro '__this_cpu_add'
    #define __this_cpu_inc(pcp)  __this_cpu_add(pcp, 1)
                                 ^
   include/net/snmp.h:127:4: note: in expansion of macro '__this_cpu_inc'
       __this_cpu_inc(mib->mibs[field])
       ^
   include/net/snmp.h:192:41: note: in expansion of macro '__SNMP_INC_STATS'
    #define __SNMP_INC_STATS64(mib, field)  __SNMP_INC_STATS(mib, field)
                                            ^
   include/net/ipv6.h:171:2: note: in expansion of macro '__SNMP_INC_STATS64'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
     ^
   include/net/ipv6.h:213:3: note: in expansion of macro '_DEVINC'
      _DEVINC(net, ipv6, __, idev, field)
      ^
   include/net/ipv6_frag.h:80:2: note: in expansion of macro '__IP6_INC_STATS'
     __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
     ^
>> include/net/ipv6.h:171:34: error: 'struct netns_mib' has no member named 'ipv6_statistics'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
                                     ^
   arch/x86/include/asm/percpu.h:138:17: note: in definition of macro 'percpu_add_op'
     switch (sizeof(var)) {      \
                    ^
   include/linux/percpu-defs.h:380:11: note: in expansion of macro 'raw_cpu_add_2'
      case 2: stem##2(variable, __VA_ARGS__);break;  \
              ^
   include/linux/percpu-defs.h:424:32: note: in expansion of macro '__pcpu_size_call'
    #define raw_cpu_add(pcp, val)  __pcpu_size_call(raw_cpu_add_, pcp, val)
                                   ^
   include/linux/percpu-defs.h:460:2: note: in expansion of macro 'raw_cpu_add'
     raw_cpu_add(pcp, val);      \
     ^
   include/linux/percpu-defs.h:499:30: note: in expansion of macro '__this_cpu_add'
    #define __this_cpu_inc(pcp)  __this_cpu_add(pcp, 1)
                                 ^
   include/net/snmp.h:127:4: note: in expansion of macro '__this_cpu_inc'
       __this_cpu_inc(mib->mibs[field])
       ^
   include/net/snmp.h:192:41: note: in expansion of macro '__SNMP_INC_STATS'
    #define __SNMP_INC_STATS64(mib, field)  __SNMP_INC_STATS(mib, field)
                                            ^
   include/net/ipv6.h:171:2: note: in expansion of macro '__SNMP_INC_STATS64'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
     ^
   include/net/ipv6.h:213:3: note: in expansion of macro '_DEVINC'
      _DEVINC(net, ipv6, __, idev, field)
      ^
   include/net/ipv6_frag.h:80:2: note: in expansion of macro '__IP6_INC_STATS'
     __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
     ^
>> include/net/ipv6.h:171:34: error: 'struct netns_mib' has no member named 'ipv6_statistics'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
                                     ^
   arch/x86/include/asm/percpu.h:141:39: note: in definition of macro 'percpu_add_op'
       asm("incb "__percpu_arg(0) : "+m" (var)); \
                                          ^
   include/linux/percpu-defs.h:380:11: note: in expansion of macro 'raw_cpu_add_2'
      case 2: stem##2(variable, __VA_ARGS__);break;  \
              ^
   include/linux/percpu-defs.h:424:32: note: in expansion of macro '__pcpu_size_call'
    #define raw_cpu_add(pcp, val)  __pcpu_size_call(raw_cpu_add_, pcp, val)
                                   ^
   include/linux/percpu-defs.h:460:2: note: in expansion of macro 'raw_cpu_add'
     raw_cpu_add(pcp, val);      \
     ^
   include/linux/percpu-defs.h:499:30: note: in expansion of macro '__this_cpu_add'
    #define __this_cpu_inc(pcp)  __this_cpu_add(pcp, 1)
                                 ^
   include/net/snmp.h:127:4: note: in expansion of macro '__this_cpu_inc'
       __this_cpu_inc(mib->mibs[field])
       ^
   include/net/snmp.h:192:41: note: in expansion of macro '__SNMP_INC_STATS'
    #define __SNMP_INC_STATS64(mib, field)  __SNMP_INC_STATS(mib, field)
                                            ^
   include/net/ipv6.h:171:2: note: in expansion of macro '__SNMP_INC_STATS64'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
     ^
   include/net/ipv6.h:213:3: note: in expansion of macro '_DEVINC'
      _DEVINC(net, ipv6, __, idev, field)
      ^
   include/net/ipv6_frag.h:80:2: note: in expansion of macro '__IP6_INC_STATS'
     __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
     ^
>> include/net/ipv6.h:171:34: error: 'struct netns_mib' has no member named 'ipv6_statistics'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
                                     ^
   arch/x86/include/asm/percpu.h:143:39: note: in definition of macro 'percpu_add_op'
       asm("decb "__percpu_arg(0) : "+m" (var)); \
                                          ^
   include/linux/percpu-defs.h:380:11: note: in expansion of macro 'raw_cpu_add_2'
      case 2: stem##2(variable, __VA_ARGS__);break;  \
              ^
   include/linux/percpu-defs.h:424:32: note: in expansion of macro '__pcpu_size_call'
    #define raw_cpu_add(pcp, val)  __pcpu_size_call(raw_cpu_add_, pcp, val)
                                   ^
   include/linux/percpu-defs.h:460:2: note: in expansion of macro 'raw_cpu_add'
     raw_cpu_add(pcp, val);      \
     ^
   include/linux/percpu-defs.h:499:30: note: in expansion of macro '__this_cpu_add'
    #define __this_cpu_inc(pcp)  __this_cpu_add(pcp, 1)
                                 ^
   include/net/snmp.h:127:4: note: in expansion of macro '__this_cpu_inc'
       __this_cpu_inc(mib->mibs[field])
       ^
   include/net/snmp.h:192:41: note: in expansion of macro '__SNMP_INC_STATS'
    #define __SNMP_INC_STATS64(mib, field)  __SNMP_INC_STATS(mib, field)
                                            ^
   include/net/ipv6.h:171:2: note: in expansion of macro '__SNMP_INC_STATS64'
     mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
     ^
   include/net/ipv6.h:213:3: note: in expansion of macro '_DEVINC'
      _DEVINC(net, ipv6, __, idev, field)
      ^
   include/net/ipv6_frag.h:80:2: note: in expansion of macro '__IP6_INC_STATS'
     __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
     ^

vim +171 include/net/ipv6.h

3d7cc2ba Pavel Emelyanov   2008-01-09  165  
13415e46 Eric Dumazet      2016-04-27  166  #define _DEVINC(net, statname, mod, idev, field)			\
14878f75 David L Stevens   2007-09-16  167  ({									\
a11d206d YOSHIFUJI Hideaki 2006-11-04  168  	struct inet6_dev *_idev = (idev);				\
a11d206d YOSHIFUJI Hideaki 2006-11-04  169  	if (likely(_idev != NULL))					\
13415e46 Eric Dumazet      2016-04-27  170  		mod##SNMP_INC_STATS64((_idev)->stats.statname, (field));\
13415e46 Eric Dumazet      2016-04-27 @171  	mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\
a11d206d YOSHIFUJI Hideaki 2006-11-04  172  })
14878f75 David L Stevens   2007-09-16  173  

:::::: The code at line 171 was first introduced by commit
:::::: 13415e46c5915e2dac089de516369005fbc045f9 net: snmp: kill STATS_BH macros

:::::: TO: Eric Dumazet <edumazet@google.com>
:::::: CC: David S. Miller <davem@davemloft.net>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 30499 bytes --]

^ permalink raw reply

* Re: [bpf-next PATCH] samples/bpf: xdp_redirect_cpu handle parsing of double VLAN tagged packets
From: Daniel Borkmann @ 2018-07-13 23:13 UTC (permalink / raw)
  To: Jesper Dangaard Brouer, netdev
  Cc: florian.maury-cv, Daniel Borkmann, marek, Alexei Starovoitov
In-Reply-To: <153149249232.12554.16301790063697986772.stgit@firesoul>

On 07/13/2018 04:35 PM, Jesper Dangaard Brouer wrote:
> People noticed that the code match on IEEE 802.1ad (ETH_P_8021AD) ethertype,
> and this implies Q-in-Q or double tagged VLANs.  Thus, we better parse
> the next VLAN header too.  It is even marked as a TODO.
> 
> This is relevant for real world use-cases, as XDP cpumap redirect can be
> used when the NIC RSS hashing is broken.  E.g. the ixgbe driver HW cannot
> handle double tagged VLAN packets, and places everything into a single
> RX queue.  Using cpumap redirect, users can redistribute traffic across
> CPUs to solve this, which is faster than the network stacks RPS solution.
> 
> It is left as an exerise how to distribute the packets across CPUs.  It
> would be convenient to use the RX hash, but that is not _yet_ exposed
> to XDP programs. For now, users can code their own hash, as I've demonstrated
> in the Suricata code (where Q-in-Q is handled correctly).
> 
> Reported-by: Florian Maury <florian.maury-cv@x-cli.eu>
> Reported-by: Marek Majkowski <marek@cloudflare.com>
> Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>

Applied to bpf-next, thanks Jesper!

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox