* Re: [PATCH] net/smc: mark as BROKEN due to remote memory exposure
From: Doug Ledford @ 2017-05-16 17:12 UTC (permalink / raw)
To: David Miller
Cc: hch, Bart.VanAssche, torvalds, netdev, linux-rdma, stable, ubraun
In-Reply-To: <20170516.124129.292555623308256441.davem@davemloft.net>
On Tue, 2017-05-16 at 12:41 -0400, David Miller wrote:
> From: Doug Ledford <dledford@redhat.com>
> Date: Tue, 16 May 2017 12:36:01 -0400
>
> > On Tue, 2017-05-16 at 18:30 +0200, Christoph Hellwig wrote:
> >> On Tue, May 16, 2017 at 12:29:23PM -0400, David Miller wrote:
> >> >
> >> > I can't push back on people with silly coding style and small
> >> > semantic
> >> > issues forever. And I think I made a serious effort to keep the
> >> > patches getting posted over and over again to make sure they got
> >> > more
> >> > exposure.
> >>
> >> You can tell them to go to linux-rdma. I'm sending people to the
> >> right
> >> mailing list all the time.
> >
> > Indeed. Every single time a patch comes into linux-rdma that
> touches
> > things in net/ or include/net, unless it is exceedingly minor, I
> check
> > the To:/Cc: lines on the email and if netdev@ isn't included, or in
> the
> > case of complex/tricky items, you aren't directly Cc:ed, then I
> > specifically tell them to include netdev@ and/or you. I've even
> had
> > things like a 12 patch series that buried three netdev@ appropriate
> > patches at different points in the series and told the submitter to
> > move all of the netdev@ related patches to the front and submit
> them to
> > netdev@ so they can be reviewed as a group before I would move on
> to
> > the others. It's just what you do. I've always considered that
> part
> > of my job.
>
> To be quite honest it wasn't exceedingly clear, even to me, that this
> had such implications or was directly a RDMA thing. From my
> perspective while reviewing I saw a patch series adding it's own
> protocol stack living inside of it's own directory under net/
OK. Fair enough. That implies to me that you probably dove right into
the patches and skimmed the cover letter (http://marc.info/?l=linux-s39
0&m=148397751211964&w=2), because when I read the cover letter, it
seems pretty clear to me that this is very much RDMA related. In any
case, there are already two other code bases that live under net/ but
also involve RDMA heavily: nfs and rds. This is a third now. So, for
future reference, just like the RDMA related nfs/rds patches already
get Cc:ed to linux-rdma@, these probably should be too.
> And, if even one RDMA/infiniband person said to me "you really
> shouldn't apply this" then I would have dropped it on the spot.
I'm glad to hear that. I wish we had managed to get together on this
sooner.
--
Doug Ledford <dledford@redhat.com>
GPG KeyID: B826A3330E572FDD
Key fingerprint = AE6B 1BDA 122B 23B4 265B 1274 B826 A333 0E57 2FDD
^ permalink raw reply
* 'iw events' stops receiving events after a while on 4.9 + hacks
From: Ben Greear @ 2017-05-16 17:12 UTC (permalink / raw)
To: netdev, linux-wireless@vger.kernel.org
I have been keeping an 'iw events' program running with a perl script gathering its
output and post-processing it. This has been working for several years on 4.7 and earlier
kernels, but when testing on 4.9 overnight, I notice that 'iw events' is not showing any input. 'strace' shows
that it is waiting on recvmsg. If I start a second 'iw events' then it will get
wifi events as expected.
Are there any known issues in this area?
Thanks,
Ben
--
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc http://www.candelatech.com
^ permalink raw reply
* Re: [PATCH net v2] net: x25: fix one potential use-after-free issue
From: David Miller @ 2017-05-16 17:16 UTC (permalink / raw)
To: xiaolou4617; +Cc: andrew.hendry, nhorman, linux-x25, netdev, linux-kernel
In-Reply-To: <1494906774-16352-1-git-send-email-xiaolou4617@gmail.com>
From: linzhang <xiaolou4617@gmail.com>
Date: Tue, 16 May 2017 11:52:54 +0800
> return rc;
> -out_dev:
> +out_proc:
> + x25_unregister_sysctl();
> +out_sysctl:
> unregister_netdevice_notifier(&x25_dev_notifier);
> -out_sock:
> +out_dev:
> + dev_remove_pack(&x25_packet_type);
> sock_unregister(AF_X25);
> -out_proto:
> +out_sock:
> proto_unregister(&x25_proto);
> goto out;
> }
Please do not name the labels this way, retain the current convention.
And that is the label names what resources get released not the
resource that we failed to acquire.
So the first label, should be "out_sysctl:" because that is what we
are releasing.
^ permalink raw reply
* Re: [PATCH] net/smc: mark as BROKEN due to remote memory exposure
From: Doug Ledford @ 2017-05-16 17:20 UTC (permalink / raw)
To: David Miller
Cc: Bart.VanAssche-XdAiOPVOjttBDgjK7y7TUQ,
torvalds-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b, hch-jcswGhMUV9g,
netdev-u79uwXL29TY76Z2rM5mHXA, linux-rdma-u79uwXL29TY76Z2rM5mHXA,
stable-u79uwXL29TY76Z2rM5mHXA,
ubraun-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8
In-Reply-To: <20170516.124945.386235742645153398.davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
On Tue, 2017-05-16 at 12:49 -0400, David Miller wrote:
> From: Doug Ledford <dledford-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> Date: Tue, 16 May 2017 12:42:43 -0400
>
> > On Tue, 2017-05-16 at 12:29 -0400, David Miller wrote:
> >> From: Doug Ledford <dledford-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> >> Date: Tue, 16 May 2017 11:57:04 -0400
> >>
> >> > Regardless though, I'm rather purturbed about this entire thing.
> >> If
> >> > you are right that because this got into 4.11, it's now a done
> >> deal,
> >> > then the fact that this went through 4 review cycles on netdev@
> >> that,
> >> > as I understand it, spanned roughly one years time, and not one
> >> single
> >> > person bothered to note that this was as much an RDMA driver as
> >> > anything else, and not one person bothered to note that linux-
> rdma@
> >> was
> >> > not on the Cc: list, and not one person told the submitters that
> >> they
> >> > needed to include linux-rdma@ on the Cc: list of these
> submissions,
> >> and
> >> > you took it without any review comments from any RDMA people in
> the
> >> > course of a year, or an ack from me to show that the RDMA
> portion
> >> of
> >> > this had at least been given some sort of review, was a collosal
> >> fuckup
> >> > of cross tree maintainer cooperation.
> >>
> >> We rely on people from various areas of expertiece to contribute
> to
> >> patch review on netdev and give appropriate feedback.
> >>
> >> If you actually look through the history, I made many semantic
> >> reviews
> >> of the SMC changes, and kept pushing back.
> >>
> >> And in fact I did this several times, making them go through
> several
> >> revisions, in the hopes that someone would review more of the meat
> >> and
> >> substance of the patch set.
> >
> > If you want to walk to the mailbox, you walk to the mailbox, you
> don't
> > walk to the grocery store, to the gym, and never even go to the
> > mailbox. Likewise, if you want review from RDMA experts, most
> (maybe
> > even all) don't subscribe to netdev@ because it's too high traffic,
> you
> > don't waste time on silly semantic pushbacks, you send a single
> email
> > that says "Please get review from linux-rdma@, thank you." Don't
> beat
> > around the bush, be direct and get it over with. That's exactly
> what I
> > do for all netdev@ related patches coming to linux-rdma@ without a
> > proper Cc: to netdev@.
>
> Read my other email, it wasn't %100 clear to me that this was so
> strictly RDMA related. And I kept pushing back with semantic changes
> in part because it wasn't clear.
See my other email. I think in the fact that you are overloaded on
netdev@ you skimmed the cover letter, which is the one thing that would
have made things clear.
> So as far as I was concerned I was not necessarily going to the wrong
> store, in fact I wasn't sure what store to go to.
>
> And none of the thousands of subscribers to netdev intuit'd this
> either. Maybe there is a reason for that.
Yeah, it's an overloaded list would be my guess. I imagine no one can
keep up with it fully in truth. Maybe it's time to split some of it
out into sublists? netdev-core/netdev-ethernet/netdev-packet? I don't
know, but I know I can't keep up with it. That you do as well as you
do is probably only because you know how to not spend too much time on
any one thing. I'm sure you have people you know are submitting
important work that effects the overall net subsystem and you focus on
their stuff, but ancillary things probably only get half attention at
double speed in order to allow you to make it through the day.
> Furthermore, if netdev is too much traffic for one or two RDMA people
> to just casually subscribe to on the off chance that a situationm
> like
> this comes up, guess what it is like for me who has to read and
> review
> pretty much every single posting that is placed there?
I get it. I don't have the time to both be responsible for linux-rdma
and follow netdev. I can already tell you what would happen if I
tried. Eventually netdev would get so far behind I would just mass
delete and start over. So that doesn't solve the problem.
Anyway, we're just talking out what happened, when what we really need
to focus on is moving forward. Again, your thoughts on marking SMC
EXPERIMENTAL until it's fixed up and unfreezing the API in case we need
to adjust it to work on different link layers?
--
Doug Ledford <dledford-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
GPG KeyID: B826A3330E572FDD
Key fingerprint = AE6B 1BDA 122B 23B4 265B 1274 B826 A333 0E57 2FDD
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: Advice on user space application integration with tc
From: Cong Wang @ 2017-05-16 17:22 UTC (permalink / raw)
To: Morgan Yang; +Cc: Linux Kernel Network Developers
In-Reply-To: <CAHV_CwaesEdmR+=Kr-O+NUCwGC4KNJZvXcDV3qNmji38OtZOeg@mail.gmail.com>
On Mon, May 15, 2017 at 1:33 PM, Morgan Yang <morgan.yang1982@gmail.com> wrote:
> I tried on both stock CentOS 7.3 and Ubuntu 16.04 and tc-skbmod was not
> support (I built tc from the latest versions of iproute2). For tc-pedit,
> examples from man tc-pedit such as "pedit ex munge" were not supported, but
> "pedit munge offset" is.
act skbmod is new, it is introduced by:
commit 86da71b57383d40993cb90baafb3735cffe5d800
Author: Jamal Hadi Salim <jhs@mojatatu.com>
Date: Mon Sep 12 20:13:09 2016 -0400
net_sched: Introduce skbmod action
For pedit, "ex", as it implies, it is an extended feature which was
introduced in:
commit 71d0ed7079dffbc5cd0941d77d9b84e04109c9bb
Author: Amir Vadai <amir@vadai.me>
Date: Tue Feb 7 09:56:07 2017 +0200
net/act_pedit: Support using offset relative to the conventional
network headers
^ permalink raw reply
* [patch net-next v3 00/10] net: sched: introduce multichain support for filters
From: Jiri Pirko @ 2017-05-16 17:27 UTC (permalink / raw)
To: netdev
Cc: davem, jhs, xiyou.wangcong, dsa, edumazet, stephen, daniel,
alexander.h.duyck, simon.horman, mlxsw
From: Jiri Pirko <jiri@mellanox.com>
Currently, each classful qdisc holds one chain of filters.
This chain is traversed and each filter could be matched on, which
may lead to execution of list of actions. One of such action
could be "reclassify", which would "reset" the processing of the
filter chain.
So this filter chain could be looked at as a flat table.
Sometimes it is convenient for user to configure a hierarchy
of tables. Example usecase is encapsulation.
Hierarchy of tables is a common way how it is done in HW pipelines.
So it is much more convenient to offload this.
This patchset contains two major patches:
8/10 - This patch introduces the support for having multiple
chains of filters.
10/10 - This patch adds new control action to allow going to specified chain
The rest of the patches are smaller or bigger depencies of those 2.
Please see individual patch descriptions for details.
Corresponding iproute2 patches are appended as a reply to this cover letter.
Simple example:
$ tc qdisc add dev eth0 ingress
$ tc filter add dev eth0 parent ffff: protocol ip pref 33 flower dst_mac 52:54:00:3d:c7:6d action goto chain 11
$ tc filter add dev eth0 parent ffff: protocol ip pref 22 chain 11 flower dst_ip 192.168.40.1 action drop
$ tc filter show dev eth0 root
filter parent ffff: protocol ip pref 33 flower chain 0
filter parent ffff: protocol ip pref 33 flower chain 0 handle 0x1
dst_mac 52:54:00:3d:c7:6d
eth_type ipv4
action order 1: gact action goto chain 11
random type none pass val 0
index 2 ref 1 bind 1
filter parent ffff: protocol ip pref 22 flower chain 11
filter parent ffff: protocol ip pref 22 flower chain 11 handle 0x1
eth_type ipv4
dst_ip 192.168.40.1
action order 1: gact action drop
random type none pass val 0
index 3 ref 1 bind 1
---
v2->v3:
- 10/10 - added "unlikely" to the reclassify and goto checks
as suggested by Daniel
v1->v2:
- 09/10 - no need to push tp all the way down to actions
- 10/10 - reworked gact to generic control action as suggested by Jamal
Jiri Pirko (10):
net: sched: move tc_classify function to cls_api.c
net: sched: introduce tcf block infractructure
net: sched: rename tcf_destroy_chain helper
net: sched: replace nprio by a bool to make the function more readable
net: sched: move TC_H_MAJ macro call into tcf_auto_prio
net: sched: introduce helpers to work with filter chains
net: sched: push chain dump to a separate function
net: sched: introduce multichain support for filters
net: sched: push tp down to action init
net: sched: add termination action to allow goto chain
include/net/act_api.h | 13 +-
include/net/pkt_cls.h | 24 ++-
include/net/pkt_sched.h | 3 -
include/net/sch_generic.h | 26 ++-
include/uapi/linux/pkt_cls.h | 1 +
include/uapi/linux/rtnetlink.h | 1 +
net/core/dev.c | 5 +-
net/sched/act_api.c | 55 +++++-
net/sched/cls_api.c | 405 ++++++++++++++++++++++++++++++++---------
net/sched/sch_api.c | 50 +----
net/sched/sch_atm.c | 29 ++-
net/sched/sch_cbq.c | 21 ++-
net/sched/sch_drr.c | 15 +-
net/sched/sch_dsmark.c | 19 +-
net/sched/sch_fq_codel.c | 17 +-
net/sched/sch_hfsc.c | 21 ++-
net/sched/sch_htb.c | 28 ++-
net/sched/sch_ingress.c | 61 +++++--
net/sched/sch_multiq.c | 16 +-
net/sched/sch_prio.c | 19 +-
net/sched/sch_qfq.c | 16 +-
net/sched/sch_sfb.c | 17 +-
net/sched/sch_sfq.c | 17 +-
23 files changed, 619 insertions(+), 260 deletions(-)
--
2.9.3
^ permalink raw reply
* [patch net-next v3 01/10] net: sched: move tc_classify function to cls_api.c
From: Jiri Pirko @ 2017-05-16 17:27 UTC (permalink / raw)
To: netdev
Cc: davem, jhs, xiyou.wangcong, dsa, edumazet, stephen, daniel,
alexander.h.duyck, simon.horman, mlxsw
In-Reply-To: <20170516172802.1317-1-jiri@resnulli.us>
From: Jiri Pirko <jiri@mellanox.com>
Move tc_classify function to cls_api.c where it belongs, rename it to
fit the namespace.
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
include/net/pkt_cls.h | 9 +++++++++
include/net/pkt_sched.h | 3 ---
net/core/dev.c | 5 +++--
net/sched/cls_api.c | 42 ++++++++++++++++++++++++++++++++++++++++++
net/sched/sch_api.c | 48 ------------------------------------------------
net/sched/sch_atm.c | 2 +-
net/sched/sch_cbq.c | 2 +-
net/sched/sch_drr.c | 2 +-
net/sched/sch_dsmark.c | 2 +-
net/sched/sch_fq_codel.c | 2 +-
net/sched/sch_hfsc.c | 2 +-
net/sched/sch_htb.c | 2 +-
net/sched/sch_multiq.c | 2 +-
net/sched/sch_prio.c | 2 +-
net/sched/sch_qfq.c | 2 +-
net/sched/sch_sfb.c | 2 +-
net/sched/sch_sfq.c | 2 +-
17 files changed, 66 insertions(+), 65 deletions(-)
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index 269fd78..cb74506 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -19,10 +19,19 @@ int unregister_tcf_proto_ops(struct tcf_proto_ops *ops);
#ifdef CONFIG_NET_CLS
void tcf_destroy_chain(struct tcf_proto __rcu **fl);
+int tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp,
+ struct tcf_result *res, bool compat_mode);
+
#else
static inline void tcf_destroy_chain(struct tcf_proto __rcu **fl)
{
}
+
+static inline int tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp,
+ struct tcf_result *res, bool compat_mode)
+{
+ return TC_ACT_UNSPEC;
+}
#endif
static inline unsigned long
diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h
index bec46f6..2579c20 100644
--- a/include/net/pkt_sched.h
+++ b/include/net/pkt_sched.h
@@ -113,9 +113,6 @@ static inline void qdisc_run(struct Qdisc *q)
__qdisc_run(q);
}
-int tc_classify(struct sk_buff *skb, const struct tcf_proto *tp,
- struct tcf_result *res, bool compat_mode);
-
static inline __be16 tc_skb_protocol(const struct sk_buff *skb)
{
/* We need to take extra care in case the skb came via
diff --git a/net/core/dev.c b/net/core/dev.c
index fca407b..acd594c 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -105,6 +105,7 @@
#include <net/dst.h>
#include <net/dst_metadata.h>
#include <net/pkt_sched.h>
+#include <net/pkt_cls.h>
#include <net/checksum.h>
#include <net/xfrm.h>
#include <linux/highmem.h>
@@ -3178,7 +3179,7 @@ sch_handle_egress(struct sk_buff *skb, int *ret, struct net_device *dev)
/* qdisc_skb_cb(skb)->pkt_len was already set by the caller. */
qdisc_bstats_cpu_update(cl->q, skb);
- switch (tc_classify(skb, cl, &cl_res, false)) {
+ switch (tcf_classify(skb, cl, &cl_res, false)) {
case TC_ACT_OK:
case TC_ACT_RECLASSIFY:
skb->tc_index = TC_H_MIN(cl_res.classid);
@@ -3948,7 +3949,7 @@ sch_handle_ingress(struct sk_buff *skb, struct packet_type **pt_prev, int *ret,
skb->tc_at_ingress = 1;
qdisc_bstats_cpu_update(cl->q, skb);
- switch (tc_classify(skb, cl, &cl_res, false)) {
+ switch (tcf_classify(skb, cl, &cl_res, false)) {
case TC_ACT_OK:
case TC_ACT_RECLASSIFY:
skb->tc_index = TC_H_MIN(cl_res.classid);
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 22f88b3..a97af61 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -196,6 +196,48 @@ void tcf_destroy_chain(struct tcf_proto __rcu **fl)
}
EXPORT_SYMBOL(tcf_destroy_chain);
+/* Main classifier routine: scans classifier chain attached
+ * to this qdisc, (optionally) tests for protocol and asks
+ * specific classifiers.
+ */
+int tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp,
+ struct tcf_result *res, bool compat_mode)
+{
+ __be16 protocol = tc_skb_protocol(skb);
+ const int max_reclassify_loop = 4;
+ const struct tcf_proto *old_tp = tp;
+ int limit = 0;
+
+reclassify:
+ for (; tp; tp = rcu_dereference_bh(tp->next)) {
+ int err;
+
+ if (tp->protocol != protocol &&
+ tp->protocol != htons(ETH_P_ALL))
+ continue;
+
+ err = tp->classify(skb, tp, res);
+ if (unlikely(err == TC_ACT_RECLASSIFY && !compat_mode))
+ goto reset;
+ if (err >= 0)
+ return err;
+ }
+
+ return TC_ACT_UNSPEC; /* signal: continue lookup */
+reset:
+ if (unlikely(limit++ >= max_reclassify_loop)) {
+ net_notice_ratelimited("%s: reclassify loop, rule prio %u, protocol %02x\n",
+ tp->q->ops->id, tp->prio & 0xffff,
+ ntohs(tp->protocol));
+ return TC_ACT_SHOT;
+ }
+
+ tp = old_tp;
+ protocol = tc_skb_protocol(skb);
+ goto reclassify;
+}
+EXPORT_SYMBOL(tcf_classify);
+
/* Add/change/delete/get a filter node */
static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index e88342f..a3bcd97 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -1878,54 +1878,6 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb)
return skb->len;
}
-/* Main classifier routine: scans classifier chain attached
- * to this qdisc, (optionally) tests for protocol and asks
- * specific classifiers.
- */
-int tc_classify(struct sk_buff *skb, const struct tcf_proto *tp,
- struct tcf_result *res, bool compat_mode)
-{
- __be16 protocol = tc_skb_protocol(skb);
-#ifdef CONFIG_NET_CLS_ACT
- const int max_reclassify_loop = 4;
- const struct tcf_proto *old_tp = tp;
- int limit = 0;
-
-reclassify:
-#endif
- for (; tp; tp = rcu_dereference_bh(tp->next)) {
- int err;
-
- if (tp->protocol != protocol &&
- tp->protocol != htons(ETH_P_ALL))
- continue;
-
- err = tp->classify(skb, tp, res);
-#ifdef CONFIG_NET_CLS_ACT
- if (unlikely(err == TC_ACT_RECLASSIFY && !compat_mode))
- goto reset;
-#endif
- if (err >= 0)
- return err;
- }
-
- return TC_ACT_UNSPEC; /* signal: continue lookup */
-#ifdef CONFIG_NET_CLS_ACT
-reset:
- if (unlikely(limit++ >= max_reclassify_loop)) {
- net_notice_ratelimited("%s: reclassify loop, rule prio %u, protocol %02x\n",
- tp->q->ops->id, tp->prio & 0xffff,
- ntohs(tp->protocol));
- return TC_ACT_SHOT;
- }
-
- tp = old_tp;
- protocol = tc_skb_protocol(skb);
- goto reclassify;
-#endif
-}
-EXPORT_SYMBOL(tc_classify);
-
#ifdef CONFIG_PROC_FS
static int psched_show(struct seq_file *seq, void *v)
{
diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c
index 40cbcee..89d32fa 100644
--- a/net/sched/sch_atm.c
+++ b/net/sched/sch_atm.c
@@ -377,7 +377,7 @@ static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch,
list_for_each_entry(flow, &p->flows, list) {
fl = rcu_dereference_bh(flow->filter_list);
if (fl) {
- result = tc_classify(skb, fl, &res, true);
+ result = tcf_classify(skb, fl, &res, true);
if (result < 0)
continue;
flow = (struct atm_flow_data *)res.class;
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index 7415859..c543ea3 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -233,7 +233,7 @@ cbq_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
/*
* Step 2+n. Apply classifier.
*/
- result = tc_classify(skb, fl, &res, true);
+ result = tcf_classify(skb, fl, &res, true);
if (!fl || result < 0)
goto fallback;
diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c
index 58a8c32..446d79b 100644
--- a/net/sched/sch_drr.c
+++ b/net/sched/sch_drr.c
@@ -333,7 +333,7 @@ static struct drr_class *drr_classify(struct sk_buff *skb, struct Qdisc *sch,
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
fl = rcu_dereference_bh(q->filter_list);
- result = tc_classify(skb, fl, &res, false);
+ result = tcf_classify(skb, fl, &res, false);
if (result >= 0) {
#ifdef CONFIG_NET_CLS_ACT
switch (result) {
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c
index 1c0f877..7bc638d 100644
--- a/net/sched/sch_dsmark.c
+++ b/net/sched/sch_dsmark.c
@@ -234,7 +234,7 @@ static int dsmark_enqueue(struct sk_buff *skb, struct Qdisc *sch,
else {
struct tcf_result res;
struct tcf_proto *fl = rcu_dereference_bh(p->filter_list);
- int result = tc_classify(skb, fl, &res, false);
+ int result = tcf_classify(skb, fl, &res, false);
pr_debug("result %d class 0x%04x\n", result, res.classid);
diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c
index 9201abc..42ba81a 100644
--- a/net/sched/sch_fq_codel.c
+++ b/net/sched/sch_fq_codel.c
@@ -96,7 +96,7 @@ static unsigned int fq_codel_classify(struct sk_buff *skb, struct Qdisc *sch,
return fq_codel_hash(q, skb) + 1;
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
- result = tc_classify(skb, filter, &res, false);
+ result = tcf_classify(skb, filter, &res, false);
if (result >= 0) {
#ifdef CONFIG_NET_CLS_ACT
switch (result) {
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
index 5cb82f6..b0dcab1 100644
--- a/net/sched/sch_hfsc.c
+++ b/net/sched/sch_hfsc.c
@@ -1142,7 +1142,7 @@ hfsc_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
head = &q->root;
tcf = rcu_dereference_bh(q->root.filter_list);
- while (tcf && (result = tc_classify(skb, tcf, &res, false)) >= 0) {
+ while (tcf && (result = tcf_classify(skb, tcf, &res, false)) >= 0) {
#ifdef CONFIG_NET_CLS_ACT
switch (result) {
case TC_ACT_QUEUED:
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 570ef3b..640f5f3 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -231,7 +231,7 @@ static struct htb_class *htb_classify(struct sk_buff *skb, struct Qdisc *sch,
}
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
- while (tcf && (result = tc_classify(skb, tcf, &res, false)) >= 0) {
+ while (tcf && (result = tcf_classify(skb, tcf, &res, false)) >= 0) {
#ifdef CONFIG_NET_CLS_ACT
switch (result) {
case TC_ACT_QUEUED:
diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c
index 43a3a10..25bb9ff 100644
--- a/net/sched/sch_multiq.c
+++ b/net/sched/sch_multiq.c
@@ -46,7 +46,7 @@ multiq_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
int err;
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
- err = tc_classify(skb, fl, &res, false);
+ err = tcf_classify(skb, fl, &res, false);
#ifdef CONFIG_NET_CLS_ACT
switch (err) {
case TC_ACT_STOLEN:
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c
index 92c2e6d..7997363 100644
--- a/net/sched/sch_prio.c
+++ b/net/sched/sch_prio.c
@@ -42,7 +42,7 @@ prio_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
if (TC_H_MAJ(skb->priority) != sch->handle) {
fl = rcu_dereference_bh(q->filter_list);
- err = tc_classify(skb, fl, &res, false);
+ err = tcf_classify(skb, fl, &res, false);
#ifdef CONFIG_NET_CLS_ACT
switch (err) {
case TC_ACT_STOLEN:
diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c
index 041eba3..73c7ac3 100644
--- a/net/sched/sch_qfq.c
+++ b/net/sched/sch_qfq.c
@@ -720,7 +720,7 @@ static struct qfq_class *qfq_classify(struct sk_buff *skb, struct Qdisc *sch,
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
fl = rcu_dereference_bh(q->filter_list);
- result = tc_classify(skb, fl, &res, false);
+ result = tcf_classify(skb, fl, &res, false);
if (result >= 0) {
#ifdef CONFIG_NET_CLS_ACT
switch (result) {
diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c
index 0f77727..b2878808 100644
--- a/net/sched/sch_sfb.c
+++ b/net/sched/sch_sfb.c
@@ -259,7 +259,7 @@ static bool sfb_classify(struct sk_buff *skb, struct tcf_proto *fl,
struct tcf_result res;
int result;
- result = tc_classify(skb, fl, &res, false);
+ result = tcf_classify(skb, fl, &res, false);
if (result >= 0) {
#ifdef CONFIG_NET_CLS_ACT
switch (result) {
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 332d94b..53a641f 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -180,7 +180,7 @@ static unsigned int sfq_classify(struct sk_buff *skb, struct Qdisc *sch,
return sfq_hash(q, skb) + 1;
*qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
- result = tc_classify(skb, fl, &res, false);
+ result = tcf_classify(skb, fl, &res, false);
if (result >= 0) {
#ifdef CONFIG_NET_CLS_ACT
switch (result) {
--
2.9.3
^ permalink raw reply related
* [patch net-next v3 02/10] net: sched: introduce tcf block infractructure
From: Jiri Pirko @ 2017-05-16 17:27 UTC (permalink / raw)
To: netdev
Cc: davem, jhs, xiyou.wangcong, dsa, edumazet, stephen, daniel,
alexander.h.duyck, simon.horman, mlxsw
In-Reply-To: <20170516172802.1317-1-jiri@resnulli.us>
From: Jiri Pirko <jiri@mellanox.com>
Currently, the filter chains are direcly put into the private structures
of qdiscs. In order to be able to have multiple chains per qdisc and to
allow filter chains sharing among qdiscs, there is a need for common
object that would hold the chains. This introduces such object and calls
it "tcf_block".
Helpers to get and put the blocks are provided to be called from
individual qdisc code. Also, the original filter_list pointers are left
in qdisc privs to allow the entry into tcf_block processing without any
added overhead of possible multiple pointer dereference on fast path.
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
include/net/pkt_cls.h | 13 ++++++++--
include/net/sch_generic.h | 7 +++++-
net/sched/cls_api.c | 48 +++++++++++++++++++++++++++++--------
net/sched/sch_api.c | 2 +-
net/sched/sch_atm.c | 27 ++++++++++++++-------
net/sched/sch_cbq.c | 19 ++++++++++-----
net/sched/sch_drr.c | 13 ++++++----
net/sched/sch_dsmark.c | 17 ++++++++-----
net/sched/sch_fq_codel.c | 15 ++++++++----
net/sched/sch_hfsc.c | 19 ++++++++++-----
net/sched/sch_htb.c | 26 +++++++++++++-------
net/sched/sch_ingress.c | 61 ++++++++++++++++++++++++++++++++++-------------
net/sched/sch_multiq.c | 14 +++++++----
net/sched/sch_prio.c | 17 +++++++++----
net/sched/sch_qfq.c | 14 +++++++----
net/sched/sch_sfb.c | 15 ++++++++----
net/sched/sch_sfq.c | 15 ++++++++----
17 files changed, 243 insertions(+), 99 deletions(-)
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index cb74506..e56e715 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -18,12 +18,21 @@ int register_tcf_proto_ops(struct tcf_proto_ops *ops);
int unregister_tcf_proto_ops(struct tcf_proto_ops *ops);
#ifdef CONFIG_NET_CLS
-void tcf_destroy_chain(struct tcf_proto __rcu **fl);
+int tcf_block_get(struct tcf_block **p_block,
+ struct tcf_proto __rcu **p_filter_chain);
+void tcf_block_put(struct tcf_block *block);
int tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp,
struct tcf_result *res, bool compat_mode);
#else
-static inline void tcf_destroy_chain(struct tcf_proto __rcu **fl)
+static inline
+int tcf_block_get(struct tcf_block **p_block,
+ struct tcf_proto __rcu **p_filter_chain)
+{
+ return 0;
+}
+
+static inline void tcf_block_put(struct tcf_block *block)
{
}
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 22e5209..98cf2f2 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -153,7 +153,7 @@ struct Qdisc_class_ops {
void (*walk)(struct Qdisc *, struct qdisc_walker * arg);
/* Filter manipulation */
- struct tcf_proto __rcu ** (*tcf_chain)(struct Qdisc *, unsigned long);
+ struct tcf_block * (*tcf_block)(struct Qdisc *, unsigned long);
bool (*tcf_cl_offload)(u32 classid);
unsigned long (*bind_tcf)(struct Qdisc *, unsigned long,
u32 classid);
@@ -236,6 +236,7 @@ struct tcf_proto {
struct Qdisc *q;
void *data;
const struct tcf_proto_ops *ops;
+ struct tcf_block *block;
struct rcu_head rcu;
};
@@ -247,6 +248,10 @@ struct qdisc_skb_cb {
unsigned char data[QDISC_CB_PRIV_LEN];
};
+struct tcf_block {
+ struct tcf_proto __rcu **p_filter_chain;
+};
+
static inline void qdisc_cb_private_validate(const struct sk_buff *skb, int sz)
{
struct qdisc_skb_cb *qcb;
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index a97af61..42fdc8a 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -129,7 +129,8 @@ static inline u32 tcf_auto_prio(struct tcf_proto *tp)
}
static struct tcf_proto *tcf_proto_create(const char *kind, u32 protocol,
- u32 prio, u32 parent, struct Qdisc *q)
+ u32 prio, u32 parent, struct Qdisc *q,
+ struct tcf_block *block)
{
struct tcf_proto *tp;
int err;
@@ -165,6 +166,7 @@ static struct tcf_proto *tcf_proto_create(const char *kind, u32 protocol,
tp->prio = prio;
tp->classid = parent;
tp->q = q;
+ tp->block = block;
err = tp->ops->init(tp);
if (err) {
@@ -185,7 +187,7 @@ static void tcf_proto_destroy(struct tcf_proto *tp)
kfree_rcu(tp, rcu);
}
-void tcf_destroy_chain(struct tcf_proto __rcu **fl)
+static void tcf_destroy_chain(struct tcf_proto __rcu **fl)
{
struct tcf_proto *tp;
@@ -194,7 +196,28 @@ void tcf_destroy_chain(struct tcf_proto __rcu **fl)
tcf_proto_destroy(tp);
}
}
-EXPORT_SYMBOL(tcf_destroy_chain);
+
+int tcf_block_get(struct tcf_block **p_block,
+ struct tcf_proto __rcu **p_filter_chain)
+{
+ struct tcf_block *block = kzalloc(sizeof(*block), GFP_KERNEL);
+
+ if (!block)
+ return -ENOMEM;
+ block->p_filter_chain = p_filter_chain;
+ *p_block = block;
+ return 0;
+}
+EXPORT_SYMBOL(tcf_block_get);
+
+void tcf_block_put(struct tcf_block *block)
+{
+ if (!block)
+ return;
+ tcf_destroy_chain(block->p_filter_chain);
+ kfree(block);
+}
+EXPORT_SYMBOL(tcf_block_put);
/* Main classifier routine: scans classifier chain attached
* to this qdisc, (optionally) tests for protocol and asks
@@ -254,6 +277,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
struct Qdisc *q;
struct tcf_proto __rcu **back;
struct tcf_proto __rcu **chain;
+ struct tcf_block *block;
struct tcf_proto *next;
struct tcf_proto *tp;
const struct Qdisc_class_ops *cops;
@@ -322,7 +346,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
if (!cops)
return -EINVAL;
- if (cops->tcf_chain == NULL)
+ if (!cops->tcf_block)
return -EOPNOTSUPP;
/* Do we search for filter, attached to class? */
@@ -333,11 +357,13 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
}
/* And the last stroke */
- chain = cops->tcf_chain(q, cl);
- if (chain == NULL) {
+ block = cops->tcf_block(q, cl);
+ if (!block) {
err = -EINVAL;
goto errout;
}
+ chain = block->p_filter_chain;
+
if (n->nlmsg_type == RTM_DELTFILTER && prio == 0) {
tfilter_notify_chain(net, skb, n, chain, RTM_DELTFILTER);
tcf_destroy_chain(chain);
@@ -381,7 +407,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
nprio = TC_H_MAJ(tcf_auto_prio(rtnl_dereference(*back)));
tp = tcf_proto_create(nla_data(tca[TCA_KIND]),
- protocol, nprio, parent, q);
+ protocol, nprio, parent, q, block);
if (IS_ERR(tp)) {
err = PTR_ERR(tp);
goto errout;
@@ -550,6 +576,7 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
int s_t;
struct net_device *dev;
struct Qdisc *q;
+ struct tcf_block *block;
struct tcf_proto *tp, __rcu **chain;
struct tcmsg *tcm = nlmsg_data(cb->nlh);
unsigned long cl = 0;
@@ -571,16 +598,17 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
cops = q->ops->cl_ops;
if (!cops)
goto errout;
- if (cops->tcf_chain == NULL)
+ if (!cops->tcf_block)
goto errout;
if (TC_H_MIN(tcm->tcm_parent)) {
cl = cops->get(q, tcm->tcm_parent);
if (cl == 0)
goto errout;
}
- chain = cops->tcf_chain(q, cl);
- if (chain == NULL)
+ block = cops->tcf_block(q, cl);
+ if (!block)
goto errout;
+ chain = block->p_filter_chain;
s_t = cb->args[0];
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index a3bcd97..5d95401 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -163,7 +163,7 @@ int register_qdisc(struct Qdisc_ops *qops)
if (!(cops->get && cops->put && cops->walk && cops->leaf))
goto out_einval;
- if (cops->tcf_chain && !(cops->bind_tcf && cops->unbind_tcf))
+ if (cops->tcf_block && !(cops->bind_tcf && cops->unbind_tcf))
goto out_einval;
}
diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c
index 89d32fa..f435546 100644
--- a/net/sched/sch_atm.c
+++ b/net/sched/sch_atm.c
@@ -43,6 +43,7 @@
struct atm_flow_data {
struct Qdisc *q; /* FIFO, TBF, etc. */
struct tcf_proto __rcu *filter_list;
+ struct tcf_block *block;
struct atm_vcc *vcc; /* VCC; NULL if VCC is closed */
void (*old_pop)(struct atm_vcc *vcc,
struct sk_buff *skb); /* chaining */
@@ -143,7 +144,7 @@ static void atm_tc_put(struct Qdisc *sch, unsigned long cl)
list_del_init(&flow->list);
pr_debug("atm_tc_put: qdisc %p\n", flow->q);
qdisc_destroy(flow->q);
- tcf_destroy_chain(&flow->filter_list);
+ tcf_block_put(flow->block);
if (flow->sock) {
pr_debug("atm_tc_put: f_count %ld\n",
file_count(flow->sock->file));
@@ -274,7 +275,13 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent,
error = -ENOBUFS;
goto err_out;
}
- RCU_INIT_POINTER(flow->filter_list, NULL);
+
+ error = tcf_block_get(&flow->block, &flow->filter_list);
+ if (error) {
+ kfree(flow);
+ goto err_out;
+ }
+
flow->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, classid);
if (!flow->q)
flow->q = &noop_qdisc;
@@ -346,14 +353,13 @@ static void atm_tc_walk(struct Qdisc *sch, struct qdisc_walker *walker)
}
}
-static struct tcf_proto __rcu **atm_tc_find_tcf(struct Qdisc *sch,
- unsigned long cl)
+static struct tcf_block *atm_tc_tcf_block(struct Qdisc *sch, unsigned long cl)
{
struct atm_qdisc_data *p = qdisc_priv(sch);
struct atm_flow_data *flow = (struct atm_flow_data *)cl;
pr_debug("atm_tc_find_tcf(sch %p,[qdisc %p],flow %p)\n", sch, p, flow);
- return flow ? &flow->filter_list : &p->link.filter_list;
+ return flow ? flow->block : p->link.block;
}
/* --------------------------- Qdisc operations ---------------------------- */
@@ -524,6 +530,7 @@ static struct sk_buff *atm_tc_peek(struct Qdisc *sch)
static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt)
{
struct atm_qdisc_data *p = qdisc_priv(sch);
+ int err;
pr_debug("atm_tc_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt);
INIT_LIST_HEAD(&p->flows);
@@ -534,7 +541,11 @@ static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt)
if (!p->link.q)
p->link.q = &noop_qdisc;
pr_debug("atm_tc_init: link (%p) qdisc %p\n", &p->link, p->link.q);
- RCU_INIT_POINTER(p->link.filter_list, NULL);
+
+ err = tcf_block_get(&p->link.block, &p->link.filter_list);
+ if (err)
+ return err;
+
p->link.vcc = NULL;
p->link.sock = NULL;
p->link.classid = sch->handle;
@@ -561,7 +572,7 @@ static void atm_tc_destroy(struct Qdisc *sch)
pr_debug("atm_tc_destroy(sch %p,[qdisc %p])\n", sch, p);
list_for_each_entry(flow, &p->flows, list)
- tcf_destroy_chain(&flow->filter_list);
+ tcf_block_put(flow->block);
list_for_each_entry_safe(flow, tmp, &p->flows, list) {
if (flow->ref > 1)
@@ -646,7 +657,7 @@ static const struct Qdisc_class_ops atm_class_ops = {
.change = atm_tc_change,
.delete = atm_tc_delete,
.walk = atm_tc_walk,
- .tcf_chain = atm_tc_find_tcf,
+ .tcf_block = atm_tc_tcf_block,
.bind_tcf = atm_tc_bind_filter,
.unbind_tcf = atm_tc_put,
.dump = atm_tc_dump_class,
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index c543ea3..8dd6d0a 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -127,6 +127,7 @@ struct cbq_class {
struct tc_cbq_xstats xstats;
struct tcf_proto __rcu *filter_list;
+ struct tcf_block *block;
int refcnt;
int filters;
@@ -1405,7 +1406,7 @@ static void cbq_destroy_class(struct Qdisc *sch, struct cbq_class *cl)
WARN_ON(cl->filters);
- tcf_destroy_chain(&cl->filter_list);
+ tcf_block_put(cl->block);
qdisc_destroy(cl->q);
qdisc_put_rtab(cl->R_tab);
gen_kill_estimator(&cl->rate_est);
@@ -1430,7 +1431,7 @@ static void cbq_destroy(struct Qdisc *sch)
*/
for (h = 0; h < q->clhash.hashsize; h++) {
hlist_for_each_entry(cl, &q->clhash.hash[h], common.hnode)
- tcf_destroy_chain(&cl->filter_list);
+ tcf_block_put(cl->block);
}
for (h = 0; h < q->clhash.hashsize; h++) {
hlist_for_each_entry_safe(cl, next, &q->clhash.hash[h],
@@ -1585,12 +1586,19 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
if (cl == NULL)
goto failure;
+ err = tcf_block_get(&cl->block, &cl->filter_list);
+ if (err) {
+ kfree(cl);
+ return err;
+ }
+
if (tca[TCA_RATE]) {
err = gen_new_estimator(&cl->bstats, NULL, &cl->rate_est,
NULL,
qdisc_root_sleeping_running(sch),
tca[TCA_RATE]);
if (err) {
+ tcf_block_put(cl->block);
kfree(cl);
goto failure;
}
@@ -1688,8 +1696,7 @@ static int cbq_delete(struct Qdisc *sch, unsigned long arg)
return 0;
}
-static struct tcf_proto __rcu **cbq_find_tcf(struct Qdisc *sch,
- unsigned long arg)
+static struct tcf_block *cbq_tcf_block(struct Qdisc *sch, unsigned long arg)
{
struct cbq_sched_data *q = qdisc_priv(sch);
struct cbq_class *cl = (struct cbq_class *)arg;
@@ -1697,7 +1704,7 @@ static struct tcf_proto __rcu **cbq_find_tcf(struct Qdisc *sch,
if (cl == NULL)
cl = &q->link;
- return &cl->filter_list;
+ return cl->block;
}
static unsigned long cbq_bind_filter(struct Qdisc *sch, unsigned long parent,
@@ -1756,7 +1763,7 @@ static const struct Qdisc_class_ops cbq_class_ops = {
.change = cbq_change_class,
.delete = cbq_delete,
.walk = cbq_walk,
- .tcf_chain = cbq_find_tcf,
+ .tcf_block = cbq_tcf_block,
.bind_tcf = cbq_bind_filter,
.unbind_tcf = cbq_unbind_filter,
.dump = cbq_dump_class,
diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c
index 446d79b..5db2a28 100644
--- a/net/sched/sch_drr.c
+++ b/net/sched/sch_drr.c
@@ -36,6 +36,7 @@ struct drr_class {
struct drr_sched {
struct list_head active;
struct tcf_proto __rcu *filter_list;
+ struct tcf_block *block;
struct Qdisc_class_hash clhash;
};
@@ -190,15 +191,14 @@ static void drr_put_class(struct Qdisc *sch, unsigned long arg)
drr_destroy_class(sch, cl);
}
-static struct tcf_proto __rcu **drr_tcf_chain(struct Qdisc *sch,
- unsigned long cl)
+static struct tcf_block *drr_tcf_block(struct Qdisc *sch, unsigned long cl)
{
struct drr_sched *q = qdisc_priv(sch);
if (cl)
return NULL;
- return &q->filter_list;
+ return q->block;
}
static unsigned long drr_bind_tcf(struct Qdisc *sch, unsigned long parent,
@@ -431,6 +431,9 @@ static int drr_init_qdisc(struct Qdisc *sch, struct nlattr *opt)
struct drr_sched *q = qdisc_priv(sch);
int err;
+ err = tcf_block_get(&q->block, &q->filter_list);
+ if (err)
+ return err;
err = qdisc_class_hash_init(&q->clhash);
if (err < 0)
return err;
@@ -462,7 +465,7 @@ static void drr_destroy_qdisc(struct Qdisc *sch)
struct hlist_node *next;
unsigned int i;
- tcf_destroy_chain(&q->filter_list);
+ tcf_block_put(q->block);
for (i = 0; i < q->clhash.hashsize; i++) {
hlist_for_each_entry_safe(cl, next, &q->clhash.hash[i],
@@ -477,7 +480,7 @@ static const struct Qdisc_class_ops drr_class_ops = {
.delete = drr_delete_class,
.get = drr_get_class,
.put = drr_put_class,
- .tcf_chain = drr_tcf_chain,
+ .tcf_block = drr_tcf_block,
.bind_tcf = drr_bind_tcf,
.unbind_tcf = drr_unbind_tcf,
.graft = drr_graft_class,
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c
index 7bc638d..ba45102 100644
--- a/net/sched/sch_dsmark.c
+++ b/net/sched/sch_dsmark.c
@@ -44,6 +44,7 @@ struct mask_value {
struct dsmark_qdisc_data {
struct Qdisc *q;
struct tcf_proto __rcu *filter_list;
+ struct tcf_block *block;
struct mask_value *mv;
u16 indices;
u8 set_tc_index;
@@ -183,11 +184,11 @@ static void dsmark_walk(struct Qdisc *sch, struct qdisc_walker *walker)
}
}
-static inline struct tcf_proto __rcu **dsmark_find_tcf(struct Qdisc *sch,
- unsigned long cl)
+static struct tcf_block *dsmark_tcf_block(struct Qdisc *sch, unsigned long cl)
{
struct dsmark_qdisc_data *p = qdisc_priv(sch);
- return &p->filter_list;
+
+ return p->block;
}
/* --------------------------- Qdisc operations ---------------------------- */
@@ -332,7 +333,7 @@ static int dsmark_init(struct Qdisc *sch, struct nlattr *opt)
{
struct dsmark_qdisc_data *p = qdisc_priv(sch);
struct nlattr *tb[TCA_DSMARK_MAX + 1];
- int err = -EINVAL;
+ int err;
u32 default_index = NO_DEFAULT_INDEX;
u16 indices;
int i;
@@ -342,6 +343,10 @@ static int dsmark_init(struct Qdisc *sch, struct nlattr *opt)
if (!opt)
goto errout;
+ err = tcf_block_get(&p->block, &p->filter_list);
+ if (err)
+ return err;
+
err = nla_parse_nested(tb, TCA_DSMARK_MAX, opt, dsmark_policy, NULL);
if (err < 0)
goto errout;
@@ -400,7 +405,7 @@ static void dsmark_destroy(struct Qdisc *sch)
pr_debug("%s(sch %p,[qdisc %p])\n", __func__, sch, p);
- tcf_destroy_chain(&p->filter_list);
+ tcf_block_put(p->block);
qdisc_destroy(p->q);
if (p->mv != p->embedded)
kfree(p->mv);
@@ -468,7 +473,7 @@ static const struct Qdisc_class_ops dsmark_class_ops = {
.change = dsmark_change,
.delete = dsmark_delete,
.walk = dsmark_walk,
- .tcf_chain = dsmark_find_tcf,
+ .tcf_block = dsmark_tcf_block,
.bind_tcf = dsmark_bind_filter,
.unbind_tcf = dsmark_put,
.dump = dsmark_dump_class,
diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c
index 42ba81a..f201e73 100644
--- a/net/sched/sch_fq_codel.c
+++ b/net/sched/sch_fq_codel.c
@@ -55,6 +55,7 @@ struct fq_codel_flow {
struct fq_codel_sched_data {
struct tcf_proto __rcu *filter_list; /* optional external classifier */
+ struct tcf_block *block;
struct fq_codel_flow *flows; /* Flows table [flows_cnt] */
u32 *backlogs; /* backlog table [flows_cnt] */
u32 flows_cnt; /* number of flows */
@@ -450,7 +451,7 @@ static void fq_codel_destroy(struct Qdisc *sch)
{
struct fq_codel_sched_data *q = qdisc_priv(sch);
- tcf_destroy_chain(&q->filter_list);
+ tcf_block_put(q->block);
kvfree(q->backlogs);
kvfree(q->flows);
}
@@ -459,6 +460,7 @@ static int fq_codel_init(struct Qdisc *sch, struct nlattr *opt)
{
struct fq_codel_sched_data *q = qdisc_priv(sch);
int i;
+ int err;
sch->limit = 10*1024;
q->flows_cnt = 1024;
@@ -478,6 +480,10 @@ static int fq_codel_init(struct Qdisc *sch, struct nlattr *opt)
return err;
}
+ err = tcf_block_get(&q->block, &q->filter_list);
+ if (err)
+ return err;
+
if (!q->flows) {
q->flows = kvzalloc(q->flows_cnt *
sizeof(struct fq_codel_flow), GFP_KERNEL);
@@ -589,14 +595,13 @@ static void fq_codel_put(struct Qdisc *q, unsigned long cl)
{
}
-static struct tcf_proto __rcu **fq_codel_find_tcf(struct Qdisc *sch,
- unsigned long cl)
+static struct tcf_block *fq_codel_tcf_block(struct Qdisc *sch, unsigned long cl)
{
struct fq_codel_sched_data *q = qdisc_priv(sch);
if (cl)
return NULL;
- return &q->filter_list;
+ return q->block;
}
static int fq_codel_dump_class(struct Qdisc *sch, unsigned long cl,
@@ -679,7 +684,7 @@ static const struct Qdisc_class_ops fq_codel_class_ops = {
.leaf = fq_codel_leaf,
.get = fq_codel_get,
.put = fq_codel_put,
- .tcf_chain = fq_codel_find_tcf,
+ .tcf_block = fq_codel_tcf_block,
.bind_tcf = fq_codel_bind,
.unbind_tcf = fq_codel_put,
.dump = fq_codel_dump_class,
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
index b0dcab1..a324f84 100644
--- a/net/sched/sch_hfsc.c
+++ b/net/sched/sch_hfsc.c
@@ -116,6 +116,7 @@ struct hfsc_class {
struct gnet_stats_queue qstats;
struct net_rate_estimator __rcu *rate_est;
struct tcf_proto __rcu *filter_list; /* filter list */
+ struct tcf_block *block;
unsigned int filter_cnt; /* filter count */
unsigned int level; /* class level in hierarchy */
@@ -1040,12 +1041,19 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
if (cl == NULL)
return -ENOBUFS;
+ err = tcf_block_get(&cl->block, &cl->filter_list);
+ if (err) {
+ kfree(cl);
+ return err;
+ }
+
if (tca[TCA_RATE]) {
err = gen_new_estimator(&cl->bstats, NULL, &cl->rate_est,
NULL,
qdisc_root_sleeping_running(sch),
tca[TCA_RATE]);
if (err) {
+ tcf_block_put(cl->block);
kfree(cl);
return err;
}
@@ -1091,7 +1099,7 @@ hfsc_destroy_class(struct Qdisc *sch, struct hfsc_class *cl)
{
struct hfsc_sched *q = qdisc_priv(sch);
- tcf_destroy_chain(&cl->filter_list);
+ tcf_block_put(cl->block);
qdisc_destroy(cl->qdisc);
gen_kill_estimator(&cl->rate_est);
if (cl != &q->root)
@@ -1261,8 +1269,7 @@ hfsc_unbind_tcf(struct Qdisc *sch, unsigned long arg)
cl->filter_cnt--;
}
-static struct tcf_proto __rcu **
-hfsc_tcf_chain(struct Qdisc *sch, unsigned long arg)
+static struct tcf_block *hfsc_tcf_block(struct Qdisc *sch, unsigned long arg)
{
struct hfsc_sched *q = qdisc_priv(sch);
struct hfsc_class *cl = (struct hfsc_class *)arg;
@@ -1270,7 +1277,7 @@ hfsc_tcf_chain(struct Qdisc *sch, unsigned long arg)
if (cl == NULL)
cl = &q->root;
- return &cl->filter_list;
+ return cl->block;
}
static int
@@ -1515,7 +1522,7 @@ hfsc_destroy_qdisc(struct Qdisc *sch)
for (i = 0; i < q->clhash.hashsize; i++) {
hlist_for_each_entry(cl, &q->clhash.hash[i], cl_common.hnode)
- tcf_destroy_chain(&cl->filter_list);
+ tcf_block_put(cl->block);
}
for (i = 0; i < q->clhash.hashsize; i++) {
hlist_for_each_entry_safe(cl, next, &q->clhash.hash[i],
@@ -1662,7 +1669,7 @@ static const struct Qdisc_class_ops hfsc_class_ops = {
.put = hfsc_put_class,
.bind_tcf = hfsc_bind_tcf,
.unbind_tcf = hfsc_unbind_tcf,
- .tcf_chain = hfsc_tcf_chain,
+ .tcf_block = hfsc_tcf_block,
.dump = hfsc_dump_class,
.dump_stats = hfsc_dump_class_stats,
.walk = hfsc_walk
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 640f5f3..195bbca9 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -105,6 +105,7 @@ struct htb_class {
int quantum; /* but stored for parent-to-leaf return */
struct tcf_proto __rcu *filter_list; /* class attached filters */
+ struct tcf_block *block;
int filter_cnt;
int refcnt; /* usage count of this class */
@@ -156,6 +157,7 @@ struct htb_sched {
/* filters for qdisc itself */
struct tcf_proto __rcu *filter_list;
+ struct tcf_block *block;
#define HTB_WARN_TOOMANYEVENTS 0x1
unsigned int warned; /* only one warning */
@@ -1017,6 +1019,10 @@ static int htb_init(struct Qdisc *sch, struct nlattr *opt)
if (!opt)
return -EINVAL;
+ err = tcf_block_get(&q->block, &q->filter_list);
+ if (err)
+ return err;
+
err = nla_parse_nested(tb, TCA_HTB_MAX, opt, htb_policy, NULL);
if (err < 0)
return err;
@@ -1230,7 +1236,7 @@ static void htb_destroy_class(struct Qdisc *sch, struct htb_class *cl)
qdisc_destroy(cl->un.leaf.q);
}
gen_kill_estimator(&cl->rate_est);
- tcf_destroy_chain(&cl->filter_list);
+ tcf_block_put(cl->block);
kfree(cl);
}
@@ -1248,11 +1254,11 @@ static void htb_destroy(struct Qdisc *sch)
* because filter need its target class alive to be able to call
* unbind_filter on it (without Oops).
*/
- tcf_destroy_chain(&q->filter_list);
+ tcf_block_put(q->block);
for (i = 0; i < q->clhash.hashsize; i++) {
hlist_for_each_entry(cl, &q->clhash.hash[i], common.hnode)
- tcf_destroy_chain(&cl->filter_list);
+ tcf_block_put(cl->block);
}
for (i = 0; i < q->clhash.hashsize; i++) {
hlist_for_each_entry_safe(cl, next, &q->clhash.hash[i],
@@ -1396,6 +1402,11 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
if (!cl)
goto failure;
+ err = tcf_block_get(&cl->block, &cl->filter_list);
+ if (err) {
+ kfree(cl);
+ goto failure;
+ }
if (htb_rate_est || tca[TCA_RATE]) {
err = gen_new_estimator(&cl->bstats, NULL,
&cl->rate_est,
@@ -1403,6 +1414,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
qdisc_root_sleeping_running(sch),
tca[TCA_RATE] ? : &est.nla);
if (err) {
+ tcf_block_put(cl->block);
kfree(cl);
goto failure;
}
@@ -1521,14 +1533,12 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
return err;
}
-static struct tcf_proto __rcu **htb_find_tcf(struct Qdisc *sch,
- unsigned long arg)
+static struct tcf_block *htb_tcf_block(struct Qdisc *sch, unsigned long arg)
{
struct htb_sched *q = qdisc_priv(sch);
struct htb_class *cl = (struct htb_class *)arg;
- struct tcf_proto __rcu **fl = cl ? &cl->filter_list : &q->filter_list;
- return fl;
+ return cl ? cl->block : q->block;
}
static unsigned long htb_bind_filter(struct Qdisc *sch, unsigned long parent,
@@ -1591,7 +1601,7 @@ static const struct Qdisc_class_ops htb_class_ops = {
.change = htb_change_class,
.delete = htb_delete,
.walk = htb_walk,
- .tcf_chain = htb_find_tcf,
+ .tcf_block = htb_tcf_block,
.bind_tcf = htb_bind_filter,
.unbind_tcf = htb_unbind_filter,
.dump = htb_dump_class,
diff --git a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c
index 3bab5f6..d8a9beb 100644
--- a/net/sched/sch_ingress.c
+++ b/net/sched/sch_ingress.c
@@ -18,6 +18,10 @@
#include <net/pkt_sched.h>
#include <net/pkt_cls.h>
+struct ingress_sched_data {
+ struct tcf_block *block;
+};
+
static struct Qdisc *ingress_leaf(struct Qdisc *sch, unsigned long arg)
{
return NULL;
@@ -47,16 +51,23 @@ static void ingress_walk(struct Qdisc *sch, struct qdisc_walker *walker)
{
}
-static struct tcf_proto __rcu **ingress_find_tcf(struct Qdisc *sch,
- unsigned long cl)
+static struct tcf_block *ingress_tcf_block(struct Qdisc *sch, unsigned long cl)
{
- struct net_device *dev = qdisc_dev(sch);
+ struct ingress_sched_data *q = qdisc_priv(sch);
- return &dev->ingress_cl_list;
+ return q->block;
}
static int ingress_init(struct Qdisc *sch, struct nlattr *opt)
{
+ struct ingress_sched_data *q = qdisc_priv(sch);
+ struct net_device *dev = qdisc_dev(sch);
+ int err;
+
+ err = tcf_block_get(&q->block, &dev->ingress_cl_list);
+ if (err)
+ return err;
+
net_inc_ingress_queue();
sch->flags |= TCQ_F_CPUSTATS;
@@ -65,9 +76,9 @@ static int ingress_init(struct Qdisc *sch, struct nlattr *opt)
static void ingress_destroy(struct Qdisc *sch)
{
- struct net_device *dev = qdisc_dev(sch);
+ struct ingress_sched_data *q = qdisc_priv(sch);
- tcf_destroy_chain(&dev->ingress_cl_list);
+ tcf_block_put(q->block);
net_dec_ingress_queue();
}
@@ -91,7 +102,7 @@ static const struct Qdisc_class_ops ingress_class_ops = {
.get = ingress_get,
.put = ingress_put,
.walk = ingress_walk,
- .tcf_chain = ingress_find_tcf,
+ .tcf_block = ingress_tcf_block,
.tcf_cl_offload = ingress_cl_offload,
.bind_tcf = ingress_bind_filter,
.unbind_tcf = ingress_put,
@@ -100,12 +111,18 @@ static const struct Qdisc_class_ops ingress_class_ops = {
static struct Qdisc_ops ingress_qdisc_ops __read_mostly = {
.cl_ops = &ingress_class_ops,
.id = "ingress",
+ .priv_size = sizeof(struct ingress_sched_data),
.init = ingress_init,
.destroy = ingress_destroy,
.dump = ingress_dump,
.owner = THIS_MODULE,
};
+struct clsact_sched_data {
+ struct tcf_block *ingress_block;
+ struct tcf_block *egress_block;
+};
+
static unsigned long clsact_get(struct Qdisc *sch, u32 classid)
{
switch (TC_H_MIN(classid)) {
@@ -128,16 +145,15 @@ static unsigned long clsact_bind_filter(struct Qdisc *sch,
return clsact_get(sch, classid);
}
-static struct tcf_proto __rcu **clsact_find_tcf(struct Qdisc *sch,
- unsigned long cl)
+static struct tcf_block *clsact_tcf_block(struct Qdisc *sch, unsigned long cl)
{
- struct net_device *dev = qdisc_dev(sch);
+ struct clsact_sched_data *q = qdisc_priv(sch);
switch (cl) {
case TC_H_MIN(TC_H_MIN_INGRESS):
- return &dev->ingress_cl_list;
+ return q->ingress_block;
case TC_H_MIN(TC_H_MIN_EGRESS):
- return &dev->egress_cl_list;
+ return q->egress_block;
default:
return NULL;
}
@@ -145,6 +161,18 @@ static struct tcf_proto __rcu **clsact_find_tcf(struct Qdisc *sch,
static int clsact_init(struct Qdisc *sch, struct nlattr *opt)
{
+ struct clsact_sched_data *q = qdisc_priv(sch);
+ struct net_device *dev = qdisc_dev(sch);
+ int err;
+
+ err = tcf_block_get(&q->ingress_block, &dev->ingress_cl_list);
+ if (err)
+ return err;
+
+ err = tcf_block_get(&q->egress_block, &dev->egress_cl_list);
+ if (err)
+ return err;
+
net_inc_ingress_queue();
net_inc_egress_queue();
@@ -155,10 +183,10 @@ static int clsact_init(struct Qdisc *sch, struct nlattr *opt)
static void clsact_destroy(struct Qdisc *sch)
{
- struct net_device *dev = qdisc_dev(sch);
+ struct clsact_sched_data *q = qdisc_priv(sch);
- tcf_destroy_chain(&dev->ingress_cl_list);
- tcf_destroy_chain(&dev->egress_cl_list);
+ tcf_block_put(q->egress_block);
+ tcf_block_put(q->ingress_block);
net_dec_ingress_queue();
net_dec_egress_queue();
@@ -169,7 +197,7 @@ static const struct Qdisc_class_ops clsact_class_ops = {
.get = clsact_get,
.put = ingress_put,
.walk = ingress_walk,
- .tcf_chain = clsact_find_tcf,
+ .tcf_block = clsact_tcf_block,
.tcf_cl_offload = clsact_cl_offload,
.bind_tcf = clsact_bind_filter,
.unbind_tcf = ingress_put,
@@ -178,6 +206,7 @@ static const struct Qdisc_class_ops clsact_class_ops = {
static struct Qdisc_ops clsact_qdisc_ops __read_mostly = {
.cl_ops = &clsact_class_ops,
.id = "clsact",
+ .priv_size = sizeof(struct clsact_sched_data),
.init = clsact_init,
.destroy = clsact_destroy,
.dump = ingress_dump,
diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c
index 25bb9ff..6047674 100644
--- a/net/sched/sch_multiq.c
+++ b/net/sched/sch_multiq.c
@@ -32,6 +32,7 @@ struct multiq_sched_data {
u16 max_bands;
u16 curband;
struct tcf_proto __rcu *filter_list;
+ struct tcf_block *block;
struct Qdisc **queues;
};
@@ -170,7 +171,7 @@ multiq_destroy(struct Qdisc *sch)
int band;
struct multiq_sched_data *q = qdisc_priv(sch);
- tcf_destroy_chain(&q->filter_list);
+ tcf_block_put(q->block);
for (band = 0; band < q->bands; band++)
qdisc_destroy(q->queues[band]);
@@ -243,6 +244,10 @@ static int multiq_init(struct Qdisc *sch, struct nlattr *opt)
if (opt == NULL)
return -EINVAL;
+ err = tcf_block_get(&q->block, &q->filter_list);
+ if (err)
+ return err;
+
q->max_bands = qdisc_dev(sch)->num_tx_queues;
q->queues = kcalloc(q->max_bands, sizeof(struct Qdisc *), GFP_KERNEL);
@@ -367,14 +372,13 @@ static void multiq_walk(struct Qdisc *sch, struct qdisc_walker *arg)
}
}
-static struct tcf_proto __rcu **multiq_find_tcf(struct Qdisc *sch,
- unsigned long cl)
+static struct tcf_block *multiq_tcf_block(struct Qdisc *sch, unsigned long cl)
{
struct multiq_sched_data *q = qdisc_priv(sch);
if (cl)
return NULL;
- return &q->filter_list;
+ return q->block;
}
static const struct Qdisc_class_ops multiq_class_ops = {
@@ -383,7 +387,7 @@ static const struct Qdisc_class_ops multiq_class_ops = {
.get = multiq_get,
.put = multiq_put,
.walk = multiq_walk,
- .tcf_chain = multiq_find_tcf,
+ .tcf_block = multiq_tcf_block,
.bind_tcf = multiq_bind,
.unbind_tcf = multiq_put,
.dump = multiq_dump_class,
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c
index 7997363..a240468 100644
--- a/net/sched/sch_prio.c
+++ b/net/sched/sch_prio.c
@@ -25,6 +25,7 @@
struct prio_sched_data {
int bands;
struct tcf_proto __rcu *filter_list;
+ struct tcf_block *block;
u8 prio2band[TC_PRIO_MAX+1];
struct Qdisc *queues[TCQ_PRIO_BANDS];
};
@@ -145,7 +146,7 @@ prio_destroy(struct Qdisc *sch)
int prio;
struct prio_sched_data *q = qdisc_priv(sch);
- tcf_destroy_chain(&q->filter_list);
+ tcf_block_put(q->block);
for (prio = 0; prio < q->bands; prio++)
qdisc_destroy(q->queues[prio]);
}
@@ -204,9 +205,16 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt)
static int prio_init(struct Qdisc *sch, struct nlattr *opt)
{
+ struct prio_sched_data *q = qdisc_priv(sch);
+ int err;
+
if (!opt)
return -EINVAL;
+ err = tcf_block_get(&q->block, &q->filter_list);
+ if (err)
+ return err;
+
return prio_tune(sch, opt);
}
@@ -317,14 +325,13 @@ static void prio_walk(struct Qdisc *sch, struct qdisc_walker *arg)
}
}
-static struct tcf_proto __rcu **prio_find_tcf(struct Qdisc *sch,
- unsigned long cl)
+static struct tcf_block *prio_tcf_block(struct Qdisc *sch, unsigned long cl)
{
struct prio_sched_data *q = qdisc_priv(sch);
if (cl)
return NULL;
- return &q->filter_list;
+ return q->block;
}
static const struct Qdisc_class_ops prio_class_ops = {
@@ -333,7 +340,7 @@ static const struct Qdisc_class_ops prio_class_ops = {
.get = prio_get,
.put = prio_put,
.walk = prio_walk,
- .tcf_chain = prio_find_tcf,
+ .tcf_block = prio_tcf_block,
.bind_tcf = prio_bind,
.unbind_tcf = prio_put,
.dump = prio_dump_class,
diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c
index 73c7ac3..076ad03 100644
--- a/net/sched/sch_qfq.c
+++ b/net/sched/sch_qfq.c
@@ -182,6 +182,7 @@ struct qfq_group {
struct qfq_sched {
struct tcf_proto __rcu *filter_list;
+ struct tcf_block *block;
struct Qdisc_class_hash clhash;
u64 oldV, V; /* Precise virtual times. */
@@ -582,15 +583,14 @@ static void qfq_put_class(struct Qdisc *sch, unsigned long arg)
qfq_destroy_class(sch, cl);
}
-static struct tcf_proto __rcu **qfq_tcf_chain(struct Qdisc *sch,
- unsigned long cl)
+static struct tcf_block *qfq_tcf_block(struct Qdisc *sch, unsigned long cl)
{
struct qfq_sched *q = qdisc_priv(sch);
if (cl)
return NULL;
- return &q->filter_list;
+ return q->block;
}
static unsigned long qfq_bind_tcf(struct Qdisc *sch, unsigned long parent,
@@ -1438,6 +1438,10 @@ static int qfq_init_qdisc(struct Qdisc *sch, struct nlattr *opt)
int i, j, err;
u32 max_cl_shift, maxbudg_shift, max_classes;
+ err = tcf_block_get(&q->block, &q->filter_list);
+ if (err)
+ return err;
+
err = qdisc_class_hash_init(&q->clhash);
if (err < 0)
return err;
@@ -1492,7 +1496,7 @@ static void qfq_destroy_qdisc(struct Qdisc *sch)
struct hlist_node *next;
unsigned int i;
- tcf_destroy_chain(&q->filter_list);
+ tcf_block_put(q->block);
for (i = 0; i < q->clhash.hashsize; i++) {
hlist_for_each_entry_safe(cl, next, &q->clhash.hash[i],
@@ -1508,7 +1512,7 @@ static const struct Qdisc_class_ops qfq_class_ops = {
.delete = qfq_delete_class,
.get = qfq_get_class,
.put = qfq_put_class,
- .tcf_chain = qfq_tcf_chain,
+ .tcf_block = qfq_tcf_block,
.bind_tcf = qfq_bind_tcf,
.unbind_tcf = qfq_unbind_tcf,
.graft = qfq_graft_class,
diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c
index b2878808..9756b1c 100644
--- a/net/sched/sch_sfb.c
+++ b/net/sched/sch_sfb.c
@@ -56,6 +56,7 @@ struct sfb_bins {
struct sfb_sched_data {
struct Qdisc *qdisc;
struct tcf_proto __rcu *filter_list;
+ struct tcf_block *block;
unsigned long rehash_interval;
unsigned long warmup_time; /* double buffering warmup time in jiffies */
u32 max;
@@ -465,7 +466,7 @@ static void sfb_destroy(struct Qdisc *sch)
{
struct sfb_sched_data *q = qdisc_priv(sch);
- tcf_destroy_chain(&q->filter_list);
+ tcf_block_put(q->block);
qdisc_destroy(q->qdisc);
}
@@ -549,6 +550,11 @@ static int sfb_change(struct Qdisc *sch, struct nlattr *opt)
static int sfb_init(struct Qdisc *sch, struct nlattr *opt)
{
struct sfb_sched_data *q = qdisc_priv(sch);
+ int err;
+
+ err = tcf_block_get(&q->block, &q->filter_list);
+ if (err)
+ return err;
q->qdisc = &noop_qdisc;
return sfb_change(sch, opt);
@@ -657,14 +663,13 @@ static void sfb_walk(struct Qdisc *sch, struct qdisc_walker *walker)
}
}
-static struct tcf_proto __rcu **sfb_find_tcf(struct Qdisc *sch,
- unsigned long cl)
+static struct tcf_block *sfb_tcf_block(struct Qdisc *sch, unsigned long cl)
{
struct sfb_sched_data *q = qdisc_priv(sch);
if (cl)
return NULL;
- return &q->filter_list;
+ return q->block;
}
static unsigned long sfb_bind(struct Qdisc *sch, unsigned long parent,
@@ -682,7 +687,7 @@ static const struct Qdisc_class_ops sfb_class_ops = {
.change = sfb_change_class,
.delete = sfb_delete,
.walk = sfb_walk,
- .tcf_chain = sfb_find_tcf,
+ .tcf_block = sfb_tcf_block,
.bind_tcf = sfb_bind,
.unbind_tcf = sfb_put,
.dump = sfb_dump_class,
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 53a641f..66dfd15 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -126,6 +126,7 @@ struct sfq_sched_data {
u8 flags;
unsigned short scaled_quantum; /* SFQ_ALLOT_SIZE(quantum) */
struct tcf_proto __rcu *filter_list;
+ struct tcf_block *block;
sfq_index *ht; /* Hash table ('divisor' slots) */
struct sfq_slot *slots; /* Flows table ('maxflows' entries) */
@@ -697,7 +698,7 @@ static void sfq_destroy(struct Qdisc *sch)
{
struct sfq_sched_data *q = qdisc_priv(sch);
- tcf_destroy_chain(&q->filter_list);
+ tcf_block_put(q->block);
q->perturb_period = 0;
del_timer_sync(&q->perturb_timer);
sfq_free(q->ht);
@@ -709,6 +710,11 @@ static int sfq_init(struct Qdisc *sch, struct nlattr *opt)
{
struct sfq_sched_data *q = qdisc_priv(sch);
int i;
+ int err;
+
+ err = tcf_block_get(&q->block, &q->filter_list);
+ if (err)
+ return err;
setup_deferrable_timer(&q->perturb_timer, sfq_perturbation,
(unsigned long)sch);
@@ -815,14 +821,13 @@ static void sfq_put(struct Qdisc *q, unsigned long cl)
{
}
-static struct tcf_proto __rcu **sfq_find_tcf(struct Qdisc *sch,
- unsigned long cl)
+static struct tcf_block *sfq_tcf_block(struct Qdisc *sch, unsigned long cl)
{
struct sfq_sched_data *q = qdisc_priv(sch);
if (cl)
return NULL;
- return &q->filter_list;
+ return q->block;
}
static int sfq_dump_class(struct Qdisc *sch, unsigned long cl,
@@ -878,7 +883,7 @@ static const struct Qdisc_class_ops sfq_class_ops = {
.leaf = sfq_leaf,
.get = sfq_get,
.put = sfq_put,
- .tcf_chain = sfq_find_tcf,
+ .tcf_block = sfq_tcf_block,
.bind_tcf = sfq_bind,
.unbind_tcf = sfq_put,
.dump = sfq_dump_class,
--
2.9.3
^ permalink raw reply related
* [patch net-next v3 03/10] net: sched: rename tcf_destroy_chain helper
From: Jiri Pirko @ 2017-05-16 17:27 UTC (permalink / raw)
To: netdev
Cc: davem, jhs, xiyou.wangcong, dsa, edumazet, stephen, daniel,
alexander.h.duyck, simon.horman, mlxsw
In-Reply-To: <20170516172802.1317-1-jiri@resnulli.us>
From: Jiri Pirko <jiri@mellanox.com>
Make the name consistent with the rest of the helpers around.
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
net/sched/cls_api.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 42fdc8a..88ec1a1 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -187,7 +187,7 @@ static void tcf_proto_destroy(struct tcf_proto *tp)
kfree_rcu(tp, rcu);
}
-static void tcf_destroy_chain(struct tcf_proto __rcu **fl)
+static void tcf_chain_destroy(struct tcf_proto __rcu **fl)
{
struct tcf_proto *tp;
@@ -214,7 +214,7 @@ void tcf_block_put(struct tcf_block *block)
{
if (!block)
return;
- tcf_destroy_chain(block->p_filter_chain);
+ tcf_chain_destroy(block->p_filter_chain);
kfree(block);
}
EXPORT_SYMBOL(tcf_block_put);
@@ -366,7 +366,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
if (n->nlmsg_type == RTM_DELTFILTER && prio == 0) {
tfilter_notify_chain(net, skb, n, chain, RTM_DELTFILTER);
- tcf_destroy_chain(chain);
+ tcf_chain_destroy(chain);
err = 0;
goto errout;
}
--
2.9.3
^ permalink raw reply related
* [patch net-next v3 04/10] net: sched: replace nprio by a bool to make the function more readable
From: Jiri Pirko @ 2017-05-16 17:27 UTC (permalink / raw)
To: netdev
Cc: davem, jhs, xiyou.wangcong, dsa, edumazet, stephen, daniel,
alexander.h.duyck, simon.horman, mlxsw
In-Reply-To: <20170516172802.1317-1-jiri@resnulli.us>
From: Jiri Pirko <jiri@mellanox.com>
The use of "nprio" variable in tc_ctl_tfilter is a bit cryptic and makes
a reader wonder what is going on for a while. So help him to understand
this priority allocation dance a litte bit better.
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
net/sched/cls_api.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 88ec1a1..0e49e6e 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -271,7 +271,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
struct tcmsg *t;
u32 protocol;
u32 prio;
- u32 nprio;
+ bool prio_allocate;
u32 parent;
struct net_device *dev;
struct Qdisc *q;
@@ -300,7 +300,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
t = nlmsg_data(n);
protocol = TC_H_MIN(t->tcm_info);
prio = TC_H_MAJ(t->tcm_info);
- nprio = prio;
+ prio_allocate = false;
parent = t->tcm_parent;
cl = 0;
@@ -316,6 +316,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
*/
if (n->nlmsg_flags & NLM_F_CREATE) {
prio = TC_H_MAKE(0x80000000U, 0U);
+ prio_allocate = true;
break;
}
/* fall-through */
@@ -377,7 +378,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
back = &tp->next) {
if (tp->prio >= prio) {
if (tp->prio == prio) {
- if (!nprio ||
+ if (prio_allocate ||
(tp->protocol != protocol && protocol)) {
err = -EINVAL;
goto errout;
@@ -403,11 +404,11 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
goto errout;
}
- if (!nprio)
- nprio = TC_H_MAJ(tcf_auto_prio(rtnl_dereference(*back)));
+ if (prio_allocate)
+ prio = TC_H_MAJ(tcf_auto_prio(rtnl_dereference(*back)));
tp = tcf_proto_create(nla_data(tca[TCA_KIND]),
- protocol, nprio, parent, q, block);
+ protocol, prio, parent, q, block);
if (IS_ERR(tp)) {
err = PTR_ERR(tp);
goto errout;
--
2.9.3
^ permalink raw reply related
* [patch net-next v3 05/10] net: sched: move TC_H_MAJ macro call into tcf_auto_prio
From: Jiri Pirko @ 2017-05-16 17:27 UTC (permalink / raw)
To: netdev
Cc: davem, jhs, xiyou.wangcong, dsa, edumazet, stephen, daniel,
alexander.h.duyck, simon.horman, mlxsw
In-Reply-To: <20170516172802.1317-1-jiri@resnulli.us>
From: Jiri Pirko <jiri@mellanox.com>
Call the helper from the function rather than to always adjust the
return value of the function.
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
net/sched/cls_api.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 0e49e6e..72624fa 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -125,7 +125,7 @@ static inline u32 tcf_auto_prio(struct tcf_proto *tp)
if (tp)
first = tp->prio - 1;
- return first;
+ return TC_H_MAJ(first);
}
static struct tcf_proto *tcf_proto_create(const char *kind, u32 protocol,
@@ -405,7 +405,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
}
if (prio_allocate)
- prio = TC_H_MAJ(tcf_auto_prio(rtnl_dereference(*back)));
+ prio = tcf_auto_prio(rtnl_dereference(*back));
tp = tcf_proto_create(nla_data(tca[TCA_KIND]),
protocol, prio, parent, q, block);
--
2.9.3
^ permalink raw reply related
* [patch net-next v3 07/10] net: sched: push chain dump to a separate function
From: Jiri Pirko @ 2017-05-16 17:27 UTC (permalink / raw)
To: netdev
Cc: davem, jhs, xiyou.wangcong, dsa, edumazet, stephen, daniel,
alexander.h.duyck, simon.horman, mlxsw
In-Reply-To: <20170516172802.1317-1-jiri@resnulli.us>
From: Jiri Pirko <jiri@mellanox.com>
Since there will be multiple chains to dump, push chain dumping code to
a separate function.
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
net/sched/cls_api.c | 95 +++++++++++++++++++++++++++++------------------------
1 file changed, 52 insertions(+), 43 deletions(-)
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 6f2ea68..9f48061 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -634,21 +634,65 @@ static int tcf_node_dump(struct tcf_proto *tp, unsigned long n,
RTM_NEWTFILTER);
}
+static void tcf_chain_dump(struct tcf_chain *chain, struct sk_buff *skb,
+ struct netlink_callback *cb,
+ long index_start, long *p_index)
+{
+ struct net *net = sock_net(skb->sk);
+ struct tcmsg *tcm = nlmsg_data(cb->nlh);
+ struct tcf_dump_args arg;
+ struct tcf_proto *tp;
+
+ for (tp = rtnl_dereference(chain->filter_chain);
+ tp; tp = rtnl_dereference(tp->next), (*p_index)++) {
+ if (*p_index < index_start)
+ continue;
+ if (TC_H_MAJ(tcm->tcm_info) &&
+ TC_H_MAJ(tcm->tcm_info) != tp->prio)
+ continue;
+ if (TC_H_MIN(tcm->tcm_info) &&
+ TC_H_MIN(tcm->tcm_info) != tp->protocol)
+ continue;
+ if (*p_index > index_start)
+ memset(&cb->args[1], 0,
+ sizeof(cb->args) - sizeof(cb->args[0]));
+ if (cb->args[1] == 0) {
+ if (tcf_fill_node(net, skb, tp, 0,
+ NETLINK_CB(cb->skb).portid,
+ cb->nlh->nlmsg_seq, NLM_F_MULTI,
+ RTM_NEWTFILTER) <= 0)
+ break;
+
+ cb->args[1] = 1;
+ }
+ if (!tp->ops->walk)
+ continue;
+ arg.w.fn = tcf_node_dump;
+ arg.skb = skb;
+ arg.cb = cb;
+ arg.w.stop = 0;
+ arg.w.skip = cb->args[1] - 1;
+ arg.w.count = 0;
+ tp->ops->walk(tp, &arg.w);
+ cb->args[1] = arg.w.count + 1;
+ if (arg.w.stop)
+ break;
+ }
+}
+
/* called with RTNL */
static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
{
struct net *net = sock_net(skb->sk);
- int t;
- int s_t;
struct net_device *dev;
struct Qdisc *q;
struct tcf_block *block;
- struct tcf_proto *tp;
struct tcf_chain *chain;
struct tcmsg *tcm = nlmsg_data(cb->nlh);
unsigned long cl = 0;
const struct Qdisc_class_ops *cops;
- struct tcf_dump_args arg;
+ long index_start;
+ long index;
if (nlmsg_len(cb->nlh) < sizeof(*tcm))
return skb->len;
@@ -677,45 +721,10 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
goto errout;
chain = block->chain;
- s_t = cb->args[0];
-
- for (tp = rtnl_dereference(chain->filter_chain), t = 0;
- tp; tp = rtnl_dereference(tp->next), t++) {
- if (t < s_t)
- continue;
- if (TC_H_MAJ(tcm->tcm_info) &&
- TC_H_MAJ(tcm->tcm_info) != tp->prio)
- continue;
- if (TC_H_MIN(tcm->tcm_info) &&
- TC_H_MIN(tcm->tcm_info) != tp->protocol)
- continue;
- if (t > s_t)
- memset(&cb->args[1], 0,
- sizeof(cb->args)-sizeof(cb->args[0]));
- if (cb->args[1] == 0) {
- if (tcf_fill_node(net, skb, tp, 0,
- NETLINK_CB(cb->skb).portid,
- cb->nlh->nlmsg_seq, NLM_F_MULTI,
- RTM_NEWTFILTER) <= 0)
- break;
-
- cb->args[1] = 1;
- }
- if (tp->ops->walk == NULL)
- continue;
- arg.w.fn = tcf_node_dump;
- arg.skb = skb;
- arg.cb = cb;
- arg.w.stop = 0;
- arg.w.skip = cb->args[1] - 1;
- arg.w.count = 0;
- tp->ops->walk(tp, &arg.w);
- cb->args[1] = arg.w.count + 1;
- if (arg.w.stop)
- break;
- }
-
- cb->args[0] = t;
+ index_start = cb->args[0];
+ index = 0;
+ tcf_chain_dump(chain, skb, cb, index_start, &index);
+ cb->args[0] = index;
errout:
if (cl)
--
2.9.3
^ permalink raw reply related
* [patch net-next v3 08/10] net: sched: introduce multichain support for filters
From: Jiri Pirko @ 2017-05-16 17:28 UTC (permalink / raw)
To: netdev
Cc: davem, jhs, xiyou.wangcong, dsa, edumazet, stephen, daniel,
alexander.h.duyck, simon.horman, mlxsw
In-Reply-To: <20170516172802.1317-1-jiri@resnulli.us>
From: Jiri Pirko <jiri@mellanox.com>
Instead of having only one filter per block, introduce a list of chains
for every block. Create chain 0 by default. UAPI is extended so the user
can specify which chain he wants to change. If the new attribute is not
specified, chain 0 is used. That allows to maintain backward
compatibility. If chain does not exist and user wants to manipulate with
it, new chain is created with specified index. Also, when last filter is
removed from the chain, the chain is destroyed.
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
include/net/pkt_cls.h | 2 +
include/net/sch_generic.h | 9 +++-
include/uapi/linux/rtnetlink.h | 1 +
net/sched/cls_api.c | 104 ++++++++++++++++++++++++++++++++++-------
4 files changed, 98 insertions(+), 18 deletions(-)
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index e56e715..2c213a6 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -18,6 +18,8 @@ int register_tcf_proto_ops(struct tcf_proto_ops *ops);
int unregister_tcf_proto_ops(struct tcf_proto_ops *ops);
#ifdef CONFIG_NET_CLS
+struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index);
+void tcf_chain_put(struct tcf_chain *chain);
int tcf_block_get(struct tcf_block **p_block,
struct tcf_proto __rcu **p_filter_chain);
void tcf_block_put(struct tcf_block *block);
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 52bceed..569b565 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -8,6 +8,7 @@
#include <linux/pkt_cls.h>
#include <linux/percpu.h>
#include <linux/dynamic_queue_limits.h>
+#include <linux/list.h>
#include <net/gen_stats.h>
#include <net/rtnetlink.h>
@@ -236,7 +237,7 @@ struct tcf_proto {
struct Qdisc *q;
void *data;
const struct tcf_proto_ops *ops;
- struct tcf_block *block;
+ struct tcf_chain *chain;
struct rcu_head rcu;
};
@@ -251,10 +252,14 @@ struct qdisc_skb_cb {
struct tcf_chain {
struct tcf_proto __rcu *filter_chain;
struct tcf_proto __rcu **p_filter_chain;
+ struct list_head list;
+ struct tcf_block *block;
+ u32 index; /* chain index */
+ unsigned int refcnt;
};
struct tcf_block {
- struct tcf_chain *chain;
+ struct list_head chain_list;
};
static inline void qdisc_cb_private_validate(const struct sk_buff *skb, int sz)
diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h
index cce0613..6487b21 100644
--- a/include/uapi/linux/rtnetlink.h
+++ b/include/uapi/linux/rtnetlink.h
@@ -549,6 +549,7 @@ enum {
TCA_STAB,
TCA_PAD,
TCA_DUMP_INVISIBLE,
+ TCA_CHAIN,
__TCA_MAX
};
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 9f48061..9dcb5c5 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -129,7 +129,7 @@ static inline u32 tcf_auto_prio(struct tcf_proto *tp)
static struct tcf_proto *tcf_proto_create(const char *kind, u32 protocol,
u32 prio, u32 parent, struct Qdisc *q,
- struct tcf_block *block)
+ struct tcf_chain *chain)
{
struct tcf_proto *tp;
int err;
@@ -165,7 +165,7 @@ static struct tcf_proto *tcf_proto_create(const char *kind, u32 protocol,
tp->prio = prio;
tp->classid = parent;
tp->q = q;
- tp->block = block;
+ tp->chain = chain;
err = tp->ops->init(tp);
if (err) {
@@ -186,15 +186,26 @@ static void tcf_proto_destroy(struct tcf_proto *tp)
kfree_rcu(tp, rcu);
}
-static struct tcf_chain *tcf_chain_create(void)
+static struct tcf_chain *tcf_chain_create(struct tcf_block *block,
+ u32 chain_index)
{
- return kzalloc(sizeof(struct tcf_chain), GFP_KERNEL);
+ struct tcf_chain *chain;
+
+ chain = kzalloc(sizeof(*chain), GFP_KERNEL);
+ if (!chain)
+ return NULL;
+ list_add_tail(&chain->list, &block->chain_list);
+ chain->block = block;
+ chain->index = chain_index;
+ chain->refcnt = 1;
+ return chain;
}
static void tcf_chain_destroy(struct tcf_chain *chain)
{
struct tcf_proto *tp;
+ list_del(&chain->list);
while ((tp = rtnl_dereference(chain->filter_chain)) != NULL) {
RCU_INIT_POINTER(chain->filter_chain, tp->next);
tcf_proto_destroy(tp);
@@ -202,6 +213,30 @@ static void tcf_chain_destroy(struct tcf_chain *chain)
kfree(chain);
}
+struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index)
+{
+ struct tcf_chain *chain;
+
+ list_for_each_entry(chain, &block->chain_list, list) {
+ if (chain->index == chain_index) {
+ chain->refcnt++;
+ return chain;
+ }
+ }
+ return tcf_chain_create(block, chain_index);
+}
+EXPORT_SYMBOL(tcf_chain_get);
+
+void tcf_chain_put(struct tcf_chain *chain)
+{
+ /* Destroy unused chain, with exception of chain 0, which is the
+ * default one and has to be always present.
+ */
+ if (--chain->refcnt == 0 && !chain->filter_chain && chain->index != 0)
+ tcf_chain_destroy(chain);
+}
+EXPORT_SYMBOL(tcf_chain_put);
+
static void
tcf_chain_filter_chain_ptr_set(struct tcf_chain *chain,
struct tcf_proto __rcu **p_filter_chain)
@@ -213,16 +248,19 @@ int tcf_block_get(struct tcf_block **p_block,
struct tcf_proto __rcu **p_filter_chain)
{
struct tcf_block *block = kzalloc(sizeof(*block), GFP_KERNEL);
+ struct tcf_chain *chain;
int err;
if (!block)
return -ENOMEM;
- block->chain = tcf_chain_create();
- if (!block->chain) {
+ INIT_LIST_HEAD(&block->chain_list);
+ /* Create chain 0 by default, it has to be always present. */
+ chain = tcf_chain_create(block, 0);
+ if (!chain) {
err = -ENOMEM;
goto err_chain_create;
}
- tcf_chain_filter_chain_ptr_set(block->chain, p_filter_chain);
+ tcf_chain_filter_chain_ptr_set(chain, p_filter_chain);
*p_block = block;
return 0;
@@ -234,9 +272,13 @@ EXPORT_SYMBOL(tcf_block_get);
void tcf_block_put(struct tcf_block *block)
{
+ struct tcf_chain *chain, *tmp;
+
if (!block)
return;
- tcf_chain_destroy(block->chain);
+
+ list_for_each_entry_safe(chain, tmp, &block->chain_list, list)
+ tcf_chain_destroy(chain);
kfree(block);
}
EXPORT_SYMBOL(tcf_block_put);
@@ -354,10 +396,11 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
u32 prio;
bool prio_allocate;
u32 parent;
+ u32 chain_index;
struct net_device *dev;
struct Qdisc *q;
struct tcf_chain_info chain_info;
- struct tcf_chain *chain;
+ struct tcf_chain *chain = NULL;
struct tcf_block *block;
struct tcf_proto *tp;
const struct Qdisc_class_ops *cops;
@@ -443,7 +486,17 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
err = -EINVAL;
goto errout;
}
- chain = block->chain;
+
+ chain_index = tca[TCA_CHAIN] ? nla_get_u32(tca[TCA_CHAIN]) : 0;
+ if (chain_index > TC_ACT_EXT_VAL_MASK) {
+ err = -EINVAL;
+ goto errout;
+ }
+ chain = tcf_chain_get(block, chain_index);
+ if (!chain) {
+ err = -ENOMEM;
+ goto errout;
+ }
if (n->nlmsg_type == RTM_DELTFILTER && prio == 0) {
tfilter_notify_chain(net, skb, n, chain, RTM_DELTFILTER);
@@ -477,7 +530,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
prio = tcf_auto_prio(tcf_chain_tp_prev(&chain_info));
tp = tcf_proto_create(nla_data(tca[TCA_KIND]),
- protocol, prio, parent, q, block);
+ protocol, prio, parent, q, chain);
if (IS_ERR(tp)) {
err = PTR_ERR(tp);
goto errout;
@@ -550,6 +603,8 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
}
errout:
+ if (chain)
+ tcf_chain_put(chain);
if (cl)
cops->put(q, cl);
if (err == -EAGAIN)
@@ -578,6 +633,8 @@ static int tcf_fill_node(struct net *net, struct sk_buff *skb,
tcm->tcm_info = TC_H_MAKE(tp->prio, tp->protocol);
if (nla_put_string(skb, TCA_KIND, tp->ops->kind))
goto nla_put_failure;
+ if (nla_put_u32(skb, TCA_CHAIN, tp->chain->index))
+ goto nla_put_failure;
tcm->tcm_handle = fh;
if (RTM_DELTFILTER != event) {
tcm->tcm_handle = 0;
@@ -634,7 +691,7 @@ static int tcf_node_dump(struct tcf_proto *tp, unsigned long n,
RTM_NEWTFILTER);
}
-static void tcf_chain_dump(struct tcf_chain *chain, struct sk_buff *skb,
+static bool tcf_chain_dump(struct tcf_chain *chain, struct sk_buff *skb,
struct netlink_callback *cb,
long index_start, long *p_index)
{
@@ -661,7 +718,7 @@ static void tcf_chain_dump(struct tcf_chain *chain, struct sk_buff *skb,
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, NLM_F_MULTI,
RTM_NEWTFILTER) <= 0)
- break;
+ return false;
cb->args[1] = 1;
}
@@ -676,14 +733,16 @@ static void tcf_chain_dump(struct tcf_chain *chain, struct sk_buff *skb,
tp->ops->walk(tp, &arg.w);
cb->args[1] = arg.w.count + 1;
if (arg.w.stop)
- break;
+ return false;
}
+ return true;
}
/* called with RTNL */
static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
{
struct net *net = sock_net(skb->sk);
+ struct nlattr *tca[TCA_MAX + 1];
struct net_device *dev;
struct Qdisc *q;
struct tcf_block *block;
@@ -693,9 +752,15 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
const struct Qdisc_class_ops *cops;
long index_start;
long index;
+ int err;
if (nlmsg_len(cb->nlh) < sizeof(*tcm))
return skb->len;
+
+ err = nlmsg_parse(cb->nlh, sizeof(*tcm), tca, TCA_MAX, NULL, NULL);
+ if (err)
+ return err;
+
dev = __dev_get_by_index(net, tcm->tcm_ifindex);
if (!dev)
return skb->len;
@@ -719,11 +784,18 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
block = cops->tcf_block(q, cl);
if (!block)
goto errout;
- chain = block->chain;
index_start = cb->args[0];
index = 0;
- tcf_chain_dump(chain, skb, cb, index_start, &index);
+
+ list_for_each_entry(chain, &block->chain_list, list) {
+ if (tca[TCA_CHAIN] &&
+ nla_get_u32(tca[TCA_CHAIN]) != chain->index)
+ continue;
+ if (!tcf_chain_dump(chain, skb, cb, index_start, &index))
+ break;
+ }
+
cb->args[0] = index;
errout:
--
2.9.3
^ permalink raw reply related
* [patch net-next v3 09/10] net: sched: push tp down to action init
From: Jiri Pirko @ 2017-05-16 17:28 UTC (permalink / raw)
To: netdev
Cc: davem, jhs, xiyou.wangcong, dsa, edumazet, stephen, daniel,
alexander.h.duyck, simon.horman, mlxsw
In-Reply-To: <20170516172802.1317-1-jiri@resnulli.us>
From: Jiri Pirko <jiri@mellanox.com>
Tp pointer will be needed by the next patch in order to get the chain.
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
include/net/act_api.h | 12 ++++++------
net/sched/act_api.c | 15 ++++++++-------
net/sched/cls_api.c | 9 +++++----
3 files changed, 19 insertions(+), 17 deletions(-)
diff --git a/include/net/act_api.h b/include/net/act_api.h
index cfa2ae3..b22c6f3 100644
--- a/include/net/act_api.h
+++ b/include/net/act_api.h
@@ -180,12 +180,12 @@ int tcf_unregister_action(struct tc_action_ops *a,
int tcf_action_destroy(struct list_head *actions, int bind);
int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions,
int nr_actions, struct tcf_result *res);
-int tcf_action_init(struct net *net, struct nlattr *nla,
- struct nlattr *est, char *n, int ovr,
- int bind, struct list_head *);
-struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla,
- struct nlattr *est, char *n, int ovr,
- int bind);
+int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,
+ struct nlattr *est, char *name, int ovr, int bind,
+ struct list_head *actions);
+struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
+ struct nlattr *nla, struct nlattr *est,
+ char *name, int ovr, int bind);
int tcf_action_dump(struct sk_buff *skb, struct list_head *, int, int);
int tcf_action_dump_old(struct sk_buff *skb, struct tc_action *a, int, int);
int tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int, int);
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index a90e8f3..e389eb4 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -570,9 +570,9 @@ static struct tc_cookie *nla_memdup_cookie(struct nlattr **tb)
return c;
}
-struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla,
- struct nlattr *est, char *name, int ovr,
- int bind)
+struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
+ struct nlattr *nla, struct nlattr *est,
+ char *name, int ovr, int bind)
{
struct tc_action *a;
struct tc_action_ops *a_o;
@@ -680,8 +680,9 @@ static void cleanup_a(struct list_head *actions, int ovr)
a->tcfa_refcnt--;
}
-int tcf_action_init(struct net *net, struct nlattr *nla, struct nlattr *est,
- char *name, int ovr, int bind, struct list_head *actions)
+int tcf_action_init(struct net *net, struct tcf_proto *tp, struct nlattr *nla,
+ struct nlattr *est, char *name, int ovr, int bind,
+ struct list_head *actions)
{
struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
struct tc_action *act;
@@ -693,7 +694,7 @@ int tcf_action_init(struct net *net, struct nlattr *nla, struct nlattr *est,
return err;
for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) {
- act = tcf_action_init_1(net, tb[i], est, name, ovr, bind);
+ act = tcf_action_init_1(net, tp, tb[i], est, name, ovr, bind);
if (IS_ERR(act)) {
err = PTR_ERR(act);
goto err;
@@ -1020,7 +1021,7 @@ static int tcf_action_add(struct net *net, struct nlattr *nla,
int ret = 0;
LIST_HEAD(actions);
- ret = tcf_action_init(net, nla, NULL, NULL, ovr, 0, &actions);
+ ret = tcf_action_init(net, NULL, nla, NULL, NULL, ovr, 0, &actions);
if (ret)
return ret;
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 9dcb5c5..1112a2b 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -826,8 +826,9 @@ int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb,
struct tc_action *act;
if (exts->police && tb[exts->police]) {
- act = tcf_action_init_1(net, tb[exts->police], rate_tlv,
- "police", ovr, TCA_ACT_BIND);
+ act = tcf_action_init_1(net, tp, tb[exts->police],
+ rate_tlv, "police", ovr,
+ TCA_ACT_BIND);
if (IS_ERR(act))
return PTR_ERR(act);
@@ -838,8 +839,8 @@ int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb,
LIST_HEAD(actions);
int err, i = 0;
- err = tcf_action_init(net, tb[exts->action], rate_tlv,
- NULL, ovr, TCA_ACT_BIND,
+ err = tcf_action_init(net, tp, tb[exts->action],
+ rate_tlv, NULL, ovr, TCA_ACT_BIND,
&actions);
if (err)
return err;
--
2.9.3
^ permalink raw reply related
* [patch net-next v3 06/10] net: sched: introduce helpers to work with filter chains
From: Jiri Pirko @ 2017-05-16 17:27 UTC (permalink / raw)
To: netdev
Cc: davem, jhs, xiyou.wangcong, dsa, edumazet, stephen, daniel,
alexander.h.duyck, simon.horman, mlxsw
In-Reply-To: <20170516172802.1317-1-jiri@resnulli.us>
From: Jiri Pirko <jiri@mellanox.com>
Introduce struct tcf_chain object and set of helpers around it. Wraps up
insertion, deletion and search in the filter chain.
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
include/net/sch_generic.h | 7 ++-
net/sched/cls_api.c | 148 +++++++++++++++++++++++++++++++++-------------
2 files changed, 113 insertions(+), 42 deletions(-)
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 98cf2f2..52bceed 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -248,10 +248,15 @@ struct qdisc_skb_cb {
unsigned char data[QDISC_CB_PRIV_LEN];
};
-struct tcf_block {
+struct tcf_chain {
+ struct tcf_proto __rcu *filter_chain;
struct tcf_proto __rcu **p_filter_chain;
};
+struct tcf_block {
+ struct tcf_chain *chain;
+};
+
static inline void qdisc_cb_private_validate(const struct sk_buff *skb, int sz)
{
struct qdisc_skb_cb *qcb;
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 72624fa..6f2ea68 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -106,13 +106,12 @@ static int tfilter_notify(struct net *net, struct sk_buff *oskb,
static void tfilter_notify_chain(struct net *net, struct sk_buff *oskb,
struct nlmsghdr *n,
- struct tcf_proto __rcu **chain, int event)
+ struct tcf_chain *chain, int event)
{
- struct tcf_proto __rcu **it_chain;
struct tcf_proto *tp;
- for (it_chain = chain; (tp = rtnl_dereference(*it_chain)) != NULL;
- it_chain = &tp->next)
+ for (tp = rtnl_dereference(chain->filter_chain);
+ tp; tp = rtnl_dereference(tp->next))
tfilter_notify(net, oskb, n, tp, 0, event, false);
}
@@ -187,26 +186,49 @@ static void tcf_proto_destroy(struct tcf_proto *tp)
kfree_rcu(tp, rcu);
}
-static void tcf_chain_destroy(struct tcf_proto __rcu **fl)
+static struct tcf_chain *tcf_chain_create(void)
+{
+ return kzalloc(sizeof(struct tcf_chain), GFP_KERNEL);
+}
+
+static void tcf_chain_destroy(struct tcf_chain *chain)
{
struct tcf_proto *tp;
- while ((tp = rtnl_dereference(*fl)) != NULL) {
- RCU_INIT_POINTER(*fl, tp->next);
+ while ((tp = rtnl_dereference(chain->filter_chain)) != NULL) {
+ RCU_INIT_POINTER(chain->filter_chain, tp->next);
tcf_proto_destroy(tp);
}
+ kfree(chain);
+}
+
+static void
+tcf_chain_filter_chain_ptr_set(struct tcf_chain *chain,
+ struct tcf_proto __rcu **p_filter_chain)
+{
+ chain->p_filter_chain = p_filter_chain;
}
int tcf_block_get(struct tcf_block **p_block,
struct tcf_proto __rcu **p_filter_chain)
{
struct tcf_block *block = kzalloc(sizeof(*block), GFP_KERNEL);
+ int err;
if (!block)
return -ENOMEM;
- block->p_filter_chain = p_filter_chain;
+ block->chain = tcf_chain_create();
+ if (!block->chain) {
+ err = -ENOMEM;
+ goto err_chain_create;
+ }
+ tcf_chain_filter_chain_ptr_set(block->chain, p_filter_chain);
*p_block = block;
return 0;
+
+err_chain_create:
+ kfree(block);
+ return err;
}
EXPORT_SYMBOL(tcf_block_get);
@@ -214,7 +236,7 @@ void tcf_block_put(struct tcf_block *block)
{
if (!block)
return;
- tcf_chain_destroy(block->p_filter_chain);
+ tcf_chain_destroy(block->chain);
kfree(block);
}
EXPORT_SYMBOL(tcf_block_put);
@@ -261,6 +283,65 @@ int tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp,
}
EXPORT_SYMBOL(tcf_classify);
+struct tcf_chain_info {
+ struct tcf_proto __rcu **pprev;
+ struct tcf_proto __rcu *next;
+};
+
+static struct tcf_proto *tcf_chain_tp_prev(struct tcf_chain_info *chain_info)
+{
+ return rtnl_dereference(*chain_info->pprev);
+}
+
+static void tcf_chain_tp_insert(struct tcf_chain *chain,
+ struct tcf_chain_info *chain_info,
+ struct tcf_proto *tp)
+{
+ if (chain->p_filter_chain &&
+ *chain_info->pprev == chain->filter_chain)
+ *chain->p_filter_chain = tp;
+ RCU_INIT_POINTER(tp->next, rtnl_dereference(*chain_info->pprev));
+ rcu_assign_pointer(*chain_info->pprev, tp);
+}
+
+static void tcf_chain_tp_remove(struct tcf_chain *chain,
+ struct tcf_chain_info *chain_info,
+ struct tcf_proto *tp)
+{
+ struct tcf_proto *next = rtnl_dereference(chain_info->next);
+
+ if (chain->p_filter_chain && tp == chain->filter_chain)
+ *chain->p_filter_chain = next;
+ RCU_INIT_POINTER(*chain_info->pprev, next);
+}
+
+static struct tcf_proto *tcf_chain_tp_find(struct tcf_chain *chain,
+ struct tcf_chain_info *chain_info,
+ u32 protocol, u32 prio,
+ bool prio_allocate)
+{
+ struct tcf_proto **pprev;
+ struct tcf_proto *tp;
+
+ /* Check the chain for existence of proto-tcf with this priority */
+ for (pprev = &chain->filter_chain;
+ (tp = rtnl_dereference(*pprev)); pprev = &tp->next) {
+ if (tp->prio >= prio) {
+ if (tp->prio == prio) {
+ if (prio_allocate ||
+ (tp->protocol != protocol && protocol))
+ return ERR_PTR(-EINVAL);
+ } else {
+ tp = NULL;
+ }
+ break;
+ }
+ }
+ chain_info->pprev = pprev;
+ chain_info->next = tp ? tp->next : NULL;
+ return tp;
+}
+
/* Add/change/delete/get a filter node */
static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
@@ -275,10 +356,9 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
u32 parent;
struct net_device *dev;
struct Qdisc *q;
- struct tcf_proto __rcu **back;
- struct tcf_proto __rcu **chain;
+ struct tcf_chain_info chain_info;
+ struct tcf_chain *chain;
struct tcf_block *block;
- struct tcf_proto *next;
struct tcf_proto *tp;
const struct Qdisc_class_ops *cops;
unsigned long cl;
@@ -363,7 +443,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
err = -EINVAL;
goto errout;
}
- chain = block->p_filter_chain;
+ chain = block->chain;
if (n->nlmsg_type == RTM_DELTFILTER && prio == 0) {
tfilter_notify_chain(net, skb, n, chain, RTM_DELTFILTER);
@@ -372,22 +452,11 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
goto errout;
}
- /* Check the chain for existence of proto-tcf with this priority */
- for (back = chain;
- (tp = rtnl_dereference(*back)) != NULL;
- back = &tp->next) {
- if (tp->prio >= prio) {
- if (tp->prio == prio) {
- if (prio_allocate ||
- (tp->protocol != protocol && protocol)) {
- err = -EINVAL;
- goto errout;
- }
- } else {
- tp = NULL;
- }
- break;
- }
+ tp = tcf_chain_tp_find(chain, &chain_info, protocol,
+ prio, prio_allocate);
+ if (IS_ERR(tp)) {
+ err = PTR_ERR(tp);
+ goto errout;
}
if (tp == NULL) {
@@ -405,7 +474,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
}
if (prio_allocate)
- prio = tcf_auto_prio(rtnl_dereference(*back));
+ prio = tcf_auto_prio(tcf_chain_tp_prev(&chain_info));
tp = tcf_proto_create(nla_data(tca[TCA_KIND]),
protocol, prio, parent, q, block);
@@ -423,8 +492,7 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
if (fh == 0) {
if (n->nlmsg_type == RTM_DELTFILTER && t->tcm_handle == 0) {
- next = rtnl_dereference(tp->next);
- RCU_INIT_POINTER(*back, next);
+ tcf_chain_tp_remove(chain, &chain_info, tp);
tfilter_notify(net, skb, n, tp, fh,
RTM_DELTFILTER, false);
tcf_proto_destroy(tp);
@@ -453,11 +521,10 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
err = tp->ops->delete(tp, fh, &last);
if (err)
goto errout;
- next = rtnl_dereference(tp->next);
tfilter_notify(net, skb, n, tp, t->tcm_handle,
RTM_DELTFILTER, false);
if (last) {
- RCU_INIT_POINTER(*back, next);
+ tcf_chain_tp_remove(chain, &chain_info, tp);
tcf_proto_destroy(tp);
}
goto errout;
@@ -474,10 +541,8 @@ static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
err = tp->ops->change(net, skb, tp, cl, t->tcm_handle, tca, &fh,
n->nlmsg_flags & NLM_F_CREATE ? TCA_ACT_NOREPLACE : TCA_ACT_REPLACE);
if (err == 0) {
- if (tp_created) {
- RCU_INIT_POINTER(tp->next, rtnl_dereference(*back));
- rcu_assign_pointer(*back, tp);
- }
+ if (tp_created)
+ tcf_chain_tp_insert(chain, &chain_info, tp);
tfilter_notify(net, skb, n, tp, fh, RTM_NEWTFILTER, false);
} else {
if (tp_created)
@@ -578,7 +643,8 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
struct net_device *dev;
struct Qdisc *q;
struct tcf_block *block;
- struct tcf_proto *tp, __rcu **chain;
+ struct tcf_proto *tp;
+ struct tcf_chain *chain;
struct tcmsg *tcm = nlmsg_data(cb->nlh);
unsigned long cl = 0;
const struct Qdisc_class_ops *cops;
@@ -609,11 +675,11 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
block = cops->tcf_block(q, cl);
if (!block)
goto errout;
- chain = block->p_filter_chain;
+ chain = block->chain;
s_t = cb->args[0];
- for (tp = rtnl_dereference(*chain), t = 0;
+ for (tp = rtnl_dereference(chain->filter_chain), t = 0;
tp; tp = rtnl_dereference(tp->next), t++) {
if (t < s_t)
continue;
--
2.9.3
^ permalink raw reply related
* [patch net-next v3 10/10] net: sched: add termination action to allow goto chain
From: Jiri Pirko @ 2017-05-16 17:28 UTC (permalink / raw)
To: netdev
Cc: davem, jhs, xiyou.wangcong, dsa, edumazet, stephen, daniel,
alexander.h.duyck, simon.horman, mlxsw
In-Reply-To: <20170516172802.1317-1-jiri@resnulli.us>
From: Jiri Pirko <jiri@mellanox.com>
Introduce new type of termination action called "goto_chain". This allows
user to specify a chain to be processed. This action type is
then processed as a return value in tcf_classify loop in similar
way as "reclassify" is, only it does not reset to the first filter
in chain but rather reset to the first filter of the desired chain.
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
include/net/act_api.h | 1 +
include/net/sch_generic.h | 9 +++++++--
include/uapi/linux/pkt_cls.h | 1 +
net/sched/act_api.c | 40 ++++++++++++++++++++++++++++++++++++++++
net/sched/cls_api.c | 8 ++++++--
5 files changed, 55 insertions(+), 4 deletions(-)
diff --git a/include/net/act_api.h b/include/net/act_api.h
index b22c6f3..26ffd83 100644
--- a/include/net/act_api.h
+++ b/include/net/act_api.h
@@ -42,6 +42,7 @@ struct tc_action {
struct gnet_stats_basic_cpu __percpu *cpu_bstats;
struct gnet_stats_queue __percpu *cpu_qstats;
struct tc_cookie *act_cookie;
+ struct tcf_chain *goto_chain;
};
#define tcf_head common.tcfa_head
#define tcf_index common.tcfa_index
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 569b565..3688501 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -193,8 +193,13 @@ struct Qdisc_ops {
struct tcf_result {
- unsigned long class;
- u32 classid;
+ union {
+ struct {
+ unsigned long class;
+ u32 classid;
+ };
+ const struct tcf_proto *goto_tp;
+ };
};
struct tcf_proto_ops {
diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h
index d613be3..1b9aa9e 100644
--- a/include/uapi/linux/pkt_cls.h
+++ b/include/uapi/linux/pkt_cls.h
@@ -51,6 +51,7 @@ enum {
(((combined) & (~TC_ACT_EXT_VAL_MASK)) == opcode)
#define TC_ACT_JUMP __TC_ACT_EXT(1)
+#define TC_ACT_GOTO_CHAIN __TC_ACT_EXT(2)
/* Action type identifiers*/
enum {
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index e389eb4..0ecf2a8 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -28,6 +28,31 @@
#include <net/act_api.h>
#include <net/netlink.h>
+static int tcf_action_goto_chain_init(struct tc_action *a, struct tcf_proto *tp)
+{
+ u32 chain_index = a->tcfa_action & TC_ACT_EXT_VAL_MASK;
+
+ if (!tp)
+ return -EINVAL;
+ a->goto_chain = tcf_chain_get(tp->chain->block, chain_index);
+ if (!a->goto_chain)
+ return -ENOMEM;
+ return 0;
+}
+
+static void tcf_action_goto_chain_fini(struct tc_action *a)
+{
+ tcf_chain_put(a->goto_chain);
+}
+
+static void tcf_action_goto_chain_exec(const struct tc_action *a,
+ struct tcf_result *res)
+{
+ const struct tcf_chain *chain = a->goto_chain;
+
+ res->goto_tp = rcu_dereference_bh(chain->filter_chain);
+}
+
static void free_tcf(struct rcu_head *head)
{
struct tc_action *p = container_of(head, struct tc_action, tcfa_rcu);
@@ -39,6 +64,8 @@ static void free_tcf(struct rcu_head *head)
kfree(p->act_cookie->data);
kfree(p->act_cookie);
}
+ if (p->goto_chain)
+ tcf_action_goto_chain_fini(p);
kfree(p);
}
@@ -465,6 +492,8 @@ int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions,
else /* faulty graph, stop pipeline */
return TC_ACT_OK;
}
+ } else if (TC_ACT_EXT_CMP(ret, TC_ACT_GOTO_CHAIN)) {
+ tcf_action_goto_chain_exec(a, res);
}
if (ret != TC_ACT_PIPE)
@@ -657,6 +686,17 @@ struct tc_action *tcf_action_init_1(struct net *net, struct tcf_proto *tp,
if (err != ACT_P_CREATED)
module_put(a_o->owner);
+ if (TC_ACT_EXT_CMP(a->tcfa_action, TC_ACT_GOTO_CHAIN)) {
+ err = tcf_action_goto_chain_init(a, tp);
+ if (err) {
+ LIST_HEAD(actions);
+
+ list_add_tail(&a->list, &actions);
+ tcf_action_destroy(&actions, bind);
+ return ERR_PTR(err);
+ }
+ }
+
return a;
err_mod:
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 1112a2b..f8f2ca6 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -304,10 +304,14 @@ int tcf_classify(struct sk_buff *skb, const struct tcf_proto *tp,
continue;
err = tp->classify(skb, tp, res);
- if (unlikely(err == TC_ACT_RECLASSIFY && !compat_mode))
+ if (unlikely(err == TC_ACT_RECLASSIFY && !compat_mode)) {
goto reset;
- if (err >= 0)
+ } else if (unlikely(TC_ACT_EXT_CMP(err, TC_ACT_GOTO_CHAIN))) {
+ old_tp = res->goto_tp;
+ goto reset;
+ } else if (err >= 0) {
return err;
+ }
}
return TC_ACT_UNSPEC; /* signal: continue lookup */
--
2.9.3
^ permalink raw reply related
* [patch iproute2 v2 repost 1/3] tc_filter: add support for chain index
From: Jiri Pirko @ 2017-05-16 17:29 UTC (permalink / raw)
To: netdev
Cc: davem, jhs, xiyou.wangcong, dsa, edumazet, stephen, daniel,
alexander.h.duyck, simon.horman, mlxsw
In-Reply-To: <20170516172802.1317-1-jiri@resnulli.us>
From: Jiri Pirko <jiri@mellanox.com>
Allow user to put filter to a specific chain identified by index.
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
include/linux/rtnetlink.h | 1 +
tc/tc_filter.c | 87 +++++++++++++++++++++++++++++++++++++++--------
2 files changed, 73 insertions(+), 15 deletions(-)
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index a96db83..70c5750 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -549,6 +549,7 @@ enum {
TCA_STAB,
TCA_PAD,
TCA_DUMP_INVISIBLE,
+ TCA_CHAIN,
__TCA_MAX
};
diff --git a/tc/tc_filter.c b/tc/tc_filter.c
index ff8713b..b13fb91 100644
--- a/tc/tc_filter.c
+++ b/tc/tc_filter.c
@@ -31,7 +31,7 @@ static void usage(void)
fprintf(stderr,
"Usage: tc filter [ add | del | change | replace | show ] dev STRING\n"
"Usage: tc filter get dev STRING parent CLASSID protocol PROTO handle FILTERID pref PRIO FILTER_TYPE\n"
- " [ pref PRIO ] protocol PROTO\n"
+ " [ pref PRIO ] protocol PROTO [ chain CHAIN_INDEX ]\n"
" [ estimator INTERVAL TIME_CONSTANT ]\n"
" [ root | ingress | egress | parent CLASSID ]\n"
" [ handle FILTERID ] [ [ FILTER_TYPE ] [ help | OPTIONS ] ]\n"
@@ -59,6 +59,8 @@ static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv)
__u32 prio = 0;
__u32 protocol = 0;
int protocol_set = 0;
+ __u32 chain_index;
+ int chain_index_set = 0;
char *fhandle = NULL;
char d[16] = {};
char k[16] = {};
@@ -127,6 +129,13 @@ static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv)
invarg("invalid protocol", *argv);
protocol = id;
protocol_set = 1;
+ } else if (matches(*argv, "chain") == 0) {
+ NEXT_ARG();
+ if (chain_index_set)
+ duparg("chain", *argv);
+ if (get_u32(&chain_index, *argv, 0))
+ invarg("invalid chain index value", *argv);
+ chain_index_set = 1;
} else if (matches(*argv, "estimator") == 0) {
if (parse_estimator(&argc, &argv, &est) < 0)
return -1;
@@ -146,6 +155,9 @@ static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv)
req.t.tcm_info = TC_H_MAKE(prio<<16, protocol);
+ if (chain_index_set)
+ addattr32(&req.n, sizeof(req), TCA_CHAIN, chain_index);
+
if (k[0])
addattr_l(&req.n, sizeof(req), TCA_KIND, k, strlen(k)+1);
@@ -167,6 +179,7 @@ static int tc_filter_modify(int cmd, unsigned int flags, int argc, char **argv)
return -1;
}
}
+
if (est.ewma_log)
addattr_l(&req.n, sizeof(req), TCA_RATE, &est, sizeof(est));
@@ -193,6 +206,8 @@ static __u32 filter_parent;
static int filter_ifindex;
static __u32 filter_prio;
static __u32 filter_protocol;
+static __u32 filter_chain_index;
+static int filter_chain_index_set;
__u16 f_proto;
int print_filter(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
@@ -270,6 +285,15 @@ int print_filter(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
}
}
fprintf(fp, "%s ", rta_getattr_str(tb[TCA_KIND]));
+
+ if (tb[TCA_CHAIN]) {
+ __u32 chain_index = rta_getattr_u32(tb[TCA_CHAIN]);
+
+ if (!filter_chain_index_set ||
+ filter_chain_index != chain_index)
+ fprintf(fp, "chain %u ", chain_index);
+ }
+
q = get_filter_kind(RTA_DATA(tb[TCA_KIND]));
if (tb[TCA_OPTIONS]) {
if (q)
@@ -311,6 +335,8 @@ static int tc_filter_get(int cmd, unsigned int flags, int argc, char **argv)
__u32 prio = 0;
__u32 protocol = 0;
int protocol_set = 0;
+ __u32 chain_index;
+ int chain_index_set = 0;
__u32 parent_handle = 0;
char *fhandle = NULL;
char d[16] = {};
@@ -375,6 +401,13 @@ static int tc_filter_get(int cmd, unsigned int flags, int argc, char **argv)
invarg("invalid protocol", *argv);
protocol = id;
protocol_set = 1;
+ } else if (matches(*argv, "chain") == 0) {
+ NEXT_ARG();
+ if (chain_index_set)
+ duparg("chain", *argv);
+ if (get_u32(&chain_index, *argv, 0))
+ invarg("invalid chain index value", *argv);
+ chain_index_set = 1;
} else if (matches(*argv, "help") == 0) {
usage();
return 0;
@@ -401,6 +434,9 @@ static int tc_filter_get(int cmd, unsigned int flags, int argc, char **argv)
req.t.tcm_info = TC_H_MAKE(prio<<16, protocol);
+ if (chain_index_set)
+ addattr32(&req.n, sizeof(req), TCA_CHAIN, chain_index);
+
if (req.t.tcm_parent == TC_H_UNSPEC) {
fprintf(stderr, "Must specify filter parent\n");
return -1;
@@ -457,10 +493,20 @@ static int tc_filter_get(int cmd, unsigned int flags, int argc, char **argv)
static int tc_filter_list(int argc, char **argv)
{
- struct tcmsg t = { .tcm_family = AF_UNSPEC };
+ struct {
+ struct nlmsghdr n;
+ struct tcmsg t;
+ char buf[MAX_MSG];
+ } req = {
+ .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)),
+ .n.nlmsg_type = RTM_GETTFILTER,
+ .t.tcm_parent = TC_H_UNSPEC,
+ .t.tcm_family = AF_UNSPEC,
+ };
char d[16] = {};
__u32 prio = 0;
__u32 protocol = 0;
+ __u32 chain_index;
char *fhandle = NULL;
while (argc > 0) {
@@ -470,39 +516,39 @@ static int tc_filter_list(int argc, char **argv)
duparg("dev", *argv);
strncpy(d, *argv, sizeof(d)-1);
} else if (strcmp(*argv, "root") == 0) {
- if (t.tcm_parent) {
+ if (req.t.tcm_parent) {
fprintf(stderr,
"Error: \"root\" is duplicate parent ID\n");
return -1;
}
- filter_parent = t.tcm_parent = TC_H_ROOT;
+ filter_parent = req.t.tcm_parent = TC_H_ROOT;
} else if (strcmp(*argv, "ingress") == 0) {
- if (t.tcm_parent) {
+ if (req.t.tcm_parent) {
fprintf(stderr,
"Error: \"ingress\" is duplicate parent ID\n");
return -1;
}
filter_parent = TC_H_MAKE(TC_H_CLSACT,
TC_H_MIN_INGRESS);
- t.tcm_parent = filter_parent;
+ req.t.tcm_parent = filter_parent;
} else if (strcmp(*argv, "egress") == 0) {
- if (t.tcm_parent) {
+ if (req.t.tcm_parent) {
fprintf(stderr,
"Error: \"egress\" is duplicate parent ID\n");
return -1;
}
filter_parent = TC_H_MAKE(TC_H_CLSACT,
TC_H_MIN_EGRESS);
- t.tcm_parent = filter_parent;
+ req.t.tcm_parent = filter_parent;
} else if (strcmp(*argv, "parent") == 0) {
__u32 handle;
NEXT_ARG();
- if (t.tcm_parent)
+ if (req.t.tcm_parent)
duparg("parent", *argv);
if (get_tc_classid(&handle, *argv))
invarg("invalid parent ID", *argv);
- filter_parent = t.tcm_parent = handle;
+ filter_parent = req.t.tcm_parent = handle;
} else if (strcmp(*argv, "handle") == 0) {
NEXT_ARG();
if (fhandle)
@@ -526,6 +572,14 @@ static int tc_filter_list(int argc, char **argv)
invarg("invalid protocol", *argv);
protocol = res;
filter_protocol = protocol;
+ } else if (matches(*argv, "chain") == 0) {
+ NEXT_ARG();
+ if (filter_chain_index_set)
+ duparg("chain", *argv);
+ if (get_u32(&chain_index, *argv, 0))
+ invarg("invalid chain index value", *argv);
+ filter_chain_index_set = 1;
+ filter_chain_index = chain_index;
} else if (matches(*argv, "help") == 0) {
usage();
} else {
@@ -538,20 +592,23 @@ static int tc_filter_list(int argc, char **argv)
argc--; argv++;
}
- t.tcm_info = TC_H_MAKE(prio<<16, protocol);
+ req.t.tcm_info = TC_H_MAKE(prio<<16, protocol);
ll_init_map(&rth);
if (d[0]) {
- t.tcm_ifindex = ll_name_to_index(d);
- if (t.tcm_ifindex == 0) {
+ req.t.tcm_ifindex = ll_name_to_index(d);
+ if (req.t.tcm_ifindex == 0) {
fprintf(stderr, "Cannot find device \"%s\"\n", d);
return 1;
}
- filter_ifindex = t.tcm_ifindex;
+ filter_ifindex = req.t.tcm_ifindex;
}
- if (rtnl_dump_request(&rth, RTM_GETTFILTER, &t, sizeof(t)) < 0) {
+ if (filter_chain_index_set)
+ addattr32(&req.n, sizeof(req), TCA_CHAIN, chain_index);
+
+ if (rtnl_dump_request_n(&rth, &req.n) < 0) {
perror("Cannot send dump request");
return 1;
}
--
2.9.3
^ permalink raw reply related
* [patch iproute2 v2 repost 2/3] tc: actions: add helpers to parse and print control actions
From: Jiri Pirko @ 2017-05-16 17:29 UTC (permalink / raw)
To: netdev
Cc: davem, jhs, xiyou.wangcong, dsa, edumazet, stephen, daniel,
alexander.h.duyck, simon.horman, mlxsw
In-Reply-To: <20170516172802.1317-1-jiri@resnulli.us>
From: Jiri Pirko <jiri@mellanox.com>
Each tc action is terminated by a control action. Each action parses and
prints then intividually. Introduce set of helpers and allow to share
this code.
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
tc/m_bpf.c | 8 ++--
tc/m_connmark.c | 4 +-
tc/m_csum.c | 9 ++--
tc/m_gact.c | 44 +++++-------------
tc/m_ife.c | 10 ++--
tc/m_mirred.c | 10 ++--
tc/m_nat.c | 11 ++---
tc/m_pedit.c | 8 ++--
tc/m_police.c | 50 ++++++--------------
tc/m_sample.c | 4 +-
tc/m_simple.c | 3 --
tc/m_skbedit.c | 7 ++-
tc/m_skbmod.c | 30 ++----------
tc/m_tunnel_key.c | 8 ++--
tc/m_vlan.c | 9 ++--
tc/tc_util.c | 137 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
tc/tc_util.h | 11 ++++-
17 files changed, 210 insertions(+), 153 deletions(-)
diff --git a/tc/m_bpf.c b/tc/m_bpf.c
index 1ddc334..5728303 100644
--- a/tc/m_bpf.c
+++ b/tc/m_bpf.c
@@ -75,7 +75,7 @@ static int bpf_parse_opt(struct action_util *a, int *ptr_argc, char ***ptr_argv,
int tca_id, struct nlmsghdr *n)
{
const char *bpf_obj = NULL, *bpf_uds_name = NULL;
- struct tc_act_bpf parm = { .action = TC_ACT_PIPE };
+ struct tc_act_bpf parm = {};
struct bpf_cfg_in cfg = {};
bool seen_run = false;
struct rtattr *tail;
@@ -123,8 +123,8 @@ opt_bpf:
NEXT_ARG_FWD();
}
- if (argc && !action_a2n(*argv, &parm.action, false))
- NEXT_ARG_FWD();
+ parse_action_control_dflt(&argc, &argv, &parm.action,
+ false, TC_ACT_PIPE);
if (argc) {
if (matches(*argv, "index") == 0) {
@@ -186,7 +186,7 @@ static int bpf_print_opt(struct action_util *au, FILE *f, struct rtattr *arg)
b, sizeof(b)));
}
- fprintf(f, "default-action %s\n", action_n2a(parm->action));
+ print_action_control(f, "default-action ", parm->action, "\n");
fprintf(f, "\tindex %u ref %d bind %d", parm->index, parm->refcnt,
parm->bindcnt);
diff --git a/tc/m_connmark.c b/tc/m_connmark.c
index 295f90d..3c2274b 100644
--- a/tc/m_connmark.c
+++ b/tc/m_connmark.c
@@ -80,9 +80,7 @@ parse_connmark(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
}
}
- sel.action = TC_ACT_PIPE;
- if (argc && !action_a2n(*argv, &sel.action, false))
- NEXT_ARG_FWD();
+ parse_action_control_dflt(&argc, &argv, &sel.action, false, TC_ACT_PIPE);
if (argc) {
if (matches(*argv, "index") == 0) {
diff --git a/tc/m_csum.c b/tc/m_csum.c
index 0ee8cad..7b15673 100644
--- a/tc/m_csum.c
+++ b/tc/m_csum.c
@@ -123,8 +123,7 @@ parse_csum(struct action_util *a, int *argc_p,
return -1;
}
- if (argc && !action_a2n(*argv, &sel.action, false))
- NEXT_ARG_FWD();
+ parse_action_control_dflt(&argc, &argv, &sel.action, false, TC_ACT_OK);
if (argc) {
if (matches(*argv, "index") == 0) {
@@ -200,10 +199,10 @@ print_csum(struct action_util *au, FILE *f, struct rtattr *arg)
uflag_1 = "?empty";
}
- fprintf(f, "csum (%s%s%s%s%s%s%s) action %s\n",
+ fprintf(f, "csum (%s%s%s%s%s%s%s) ",
uflag_1, uflag_2, uflag_3,
- uflag_4, uflag_5, uflag_6, uflag_7,
- action_n2a(sel->action));
+ uflag_4, uflag_5, uflag_6, uflag_7);
+ print_action_control(f, "action ", sel->action, "\n");
fprintf(f, "\tindex %u ref %d bind %d", sel->index, sel->refcnt,
sel->bindcnt);
diff --git a/tc/m_gact.c b/tc/m_gact.c
index 755a3be..938b6b5 100644
--- a/tc/m_gact.c
+++ b/tc/m_gact.c
@@ -69,26 +69,13 @@ usage(void)
}
static int
-get_act(char ***argv_p)
-{
- int n;
-
- if (action_a2n(**argv_p, &n, false)) {
- fprintf(stderr, "bad action type %s\n", **argv_p);
- return -10;
- }
- return n;
-}
-
-static int
parse_gact(struct action_util *a, int *argc_p, char ***argv_p,
int tca_id, struct nlmsghdr *n)
{
int argc = *argc_p;
char **argv = *argv_p;
int ok = 0;
- int action = TC_POLICE_RECLASSIFY;
- struct tc_gact p = { .action = TC_POLICE_RECLASSIFY };
+ struct tc_gact p = { 0 };
#ifdef CONFIG_GACT_PROB
int rd = 0;
struct tc_gact_p pp;
@@ -102,14 +89,9 @@ parse_gact(struct action_util *a, int *argc_p, char ***argv_p,
if (matches(*argv, "gact") == 0) {
ok++;
} else {
- action = get_act(&argv);
- if (action != -10) {
- p.action = action;
- ok++;
- } else {
- explain();
- return action;
- }
+ if (parse_action_control(&argc, &argv, &p.action, false) == -1)
+ usage();
+ ok++;
}
if (ok) {
@@ -133,13 +115,9 @@ parse_gact(struct action_util *a, int *argc_p, char ***argv_p,
return -1;
}
- action = get_act(&argv);
- if (action != -10) { /* FIXME */
- pp.paction = action;
- } else {
- explain();
- return -1;
- }
+ if (parse_action_control(&argc, &argv,
+ &pp.paction, false) == -1)
+ usage();
argc--;
argv++;
if (get_u16(&pp.pval, *argv, 10)) {
@@ -212,7 +190,8 @@ print_gact(struct action_util *au, FILE * f, struct rtattr *arg)
}
p = RTA_DATA(tb[TCA_GACT_PARMS]);
- fprintf(f, "gact action %s", action_n2a(p->action));
+ fprintf(f, "gact ");
+ print_action_control(f, "action ", p->action, "");
#ifdef CONFIG_GACT_PROB
if (tb[TCA_GACT_PROB] != NULL) {
pp = RTA_DATA(tb[TCA_GACT_PROB]);
@@ -221,8 +200,9 @@ print_gact(struct action_util *au, FILE * f, struct rtattr *arg)
memset(&pp_dummy, 0, sizeof(pp_dummy));
pp = &pp_dummy;
}
- fprintf(f, "\n\t random type %s %s val %d",
- prob_n2a(pp->ptype), action_n2a(pp->paction), pp->pval);
+ fprintf(f, "\n\t random type %s", prob_n2a(pp->ptype));
+ print_action_control(f, " ", pp->paction, " ");
+ fprintf(f, "val %d", pp->pval);
#endif
fprintf(f, "\n\t index %u ref %d bind %d", p->index, p->refcnt,
p->bindcnt);
diff --git a/tc/m_ife.c b/tc/m_ife.c
index f6131b1..e3521e6 100644
--- a/tc/m_ife.c
+++ b/tc/m_ife.c
@@ -57,7 +57,7 @@ static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p,
int argc = *argc_p;
char **argv = *argv_p;
int ok = 0;
- struct tc_ife p = { .action = TC_ACT_PIPE }; /* good default */
+ struct tc_ife p = { 0 };
struct rtattr *tail;
struct rtattr *tail2;
char dbuf[ETH_ALEN];
@@ -156,8 +156,7 @@ static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p,
argv++;
}
- if (argc && !action_a2n(*argv, &p.action, false))
- NEXT_ARG_FWD();
+ parse_action_control_dflt(&argc, &argv, &p.action, false, TC_ACT_PIPE);
if (argc) {
if (matches(*argv, "index") == 0) {
@@ -245,9 +244,8 @@ static int print_ife(struct action_util *au, FILE *f, struct rtattr *arg)
}
p = RTA_DATA(tb[TCA_IFE_PARMS]);
- fprintf(f, "ife %s action %s ",
- (p->flags & IFE_ENCODE) ? "encode" : "decode",
- action_n2a(p->action));
+ fprintf(f, "ife %s ", p->flags & IFE_ENCODE ? "encode" : "decode");
+ print_action_control(f, "action ", p->action, " ");
if (tb[TCA_IFE_TYPE]) {
ife_type = rta_getattr_u16(tb[TCA_IFE_TYPE]);
diff --git a/tc/m_mirred.c b/tc/m_mirred.c
index e943890..2384bda 100644
--- a/tc/m_mirred.c
+++ b/tc/m_mirred.c
@@ -170,10 +170,8 @@ parse_direction(struct action_util *a, int *argc_p, char ***argv_p,
}
- if (argc &&
- (p.eaction == TCA_EGRESS_MIRROR || p.eaction == TCA_INGRESS_MIRROR)
- && !action_a2n(*argv, &p.action, false))
- NEXT_ARG();
+ if (p.eaction == TCA_EGRESS_MIRROR || p.eaction == TCA_INGRESS_MIRROR)
+ parse_action_control(&argc, &argv, &p.action, false);
if (argc) {
if (iok && matches(*argv, "index") == 0) {
@@ -272,8 +270,8 @@ print_mirred(struct action_util *au, FILE * f, struct rtattr *arg)
return -1;
}
- fprintf(f, "mirred (%s to device %s) %s",
- mirred_n2a(p->eaction), dev, action_n2a(p->action));
+ fprintf(f, "mirred (%s to device %s)", mirred_n2a(p->eaction), dev);
+ print_action_control(f, " ", p->action, "");
fprintf(f, "\n ");
fprintf(f, "\tindex %u ref %d bind %d", p->index, p->refcnt,
diff --git a/tc/m_nat.c b/tc/m_nat.c
index 525f185..31b68fb 100644
--- a/tc/m_nat.c
+++ b/tc/m_nat.c
@@ -115,8 +115,7 @@ parse_nat(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct
return -1;
}
- if (argc && !action_a2n(*argv, &sel.action, false))
- NEXT_ARG_FWD();
+ parse_action_control_dflt(&argc, &argv, &sel.action, false, TC_ACT_OK);
if (argc) {
if (matches(*argv, "index") == 0) {
@@ -164,12 +163,12 @@ print_nat(struct action_util *au, FILE * f, struct rtattr *arg)
len = ffs(sel->mask);
len = len ? 33 - len : 0;
- fprintf(f, " nat %s %s/%d %s %s", sel->flags & TCA_NAT_FLAG_EGRESS ?
- "egress" : "ingress",
+ fprintf(f, " nat %s %s/%d %s", sel->flags & TCA_NAT_FLAG_EGRESS ?
+ "egress" : "ingress",
format_host_r(AF_INET, 4, &sel->old_addr, buf1, sizeof(buf1)),
len,
- format_host_r(AF_INET, 4, &sel->new_addr, buf2, sizeof(buf2)),
- action_n2a(sel->action));
+ format_host_r(AF_INET, 4, &sel->new_addr, buf2, sizeof(buf2)));
+ print_action_control(f, " ", sel->action, "");
if (show_stats) {
if (tb[TCA_NAT_TM]) {
diff --git a/tc/m_pedit.c b/tc/m_pedit.c
index 6498dd9..730a434 100644
--- a/tc/m_pedit.c
+++ b/tc/m_pedit.c
@@ -625,8 +625,7 @@ int parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
return -1;
}
- if (argc && !action_a2n(*argv, &sel.sel.action, false))
- NEXT_ARG();
+ parse_action_control_dflt(&argc, &argv, &sel.sel.action, false, TC_ACT_OK);
if (argc) {
if (matches(*argv, "index") == 0) {
@@ -731,8 +730,9 @@ int print_pedit(struct action_util *au, FILE *f, struct rtattr *arg)
}
}
- fprintf(f, " pedit action %s keys %d\n ",
- action_n2a(sel->action), sel->nkeys);
+ fprintf(f, " pedit ");
+ print_action_control(f, "action ", sel->action, " ");
+ fprintf(f,"keys %d\n ", sel->nkeys);
fprintf(f, "\t index %u ref %d bind %d", sel->index, sel->refcnt,
sel->bindcnt);
diff --git a/tc/m_police.c b/tc/m_police.c
index 226e20e..2b73969 100644
--- a/tc/m_police.c
+++ b/tc/m_police.c
@@ -50,27 +50,6 @@ static void explain1(char *arg)
fprintf(stderr, "Illegal \"%s\"\n", arg);
}
-static int get_police_result(int *action, int *result, char *arg)
-{
- char *p = strchr(arg, '/');
-
- if (p)
- *p = 0;
-
- if (action_a2n(arg, action, true)) {
- if (p)
- *p = '/';
- return -1;
- }
-
- if (p) {
- *p = '/';
- if (action_a2n(p+1, result, true))
- return -1;
- }
- return 0;
-}
-
int act_parse_police(struct action_util *a, int *argc_p, char ***argv_p,
int tca_id, struct nlmsghdr *n)
{
@@ -166,23 +145,19 @@ int act_parse_police(struct action_util *a, int *argc_p, char ***argv_p,
explain1("peakrate");
return -1;
}
- } else if (matches(*argv, "reclassify") == 0) {
- p.action = TC_POLICE_RECLASSIFY;
- } else if (matches(*argv, "drop") == 0 ||
- matches(*argv, "shot") == 0) {
- p.action = TC_POLICE_SHOT;
- } else if (matches(*argv, "continue") == 0) {
- p.action = TC_POLICE_UNSPEC;
- } else if (matches(*argv, "pass") == 0) {
- p.action = TC_POLICE_OK;
- } else if (matches(*argv, "pipe") == 0) {
- p.action = TC_POLICE_PIPE;
+ } else if (matches(*argv, "reclassify") == 0 ||
+ matches(*argv, "drop") == 0 ||
+ matches(*argv, "shot") == 0 ||
+ matches(*argv, "continue") == 0 ||
+ matches(*argv, "pass") == 0 ||
+ matches(*argv, "pipe") == 0) {
+ if (parse_action_control(&argc, &argv, &p.action, false))
+ return -1;
} else if (strcmp(*argv, "conform-exceed") == 0) {
NEXT_ARG();
- if (get_police_result(&p.action, &presult, *argv)) {
- fprintf(stderr, "Illegal \"action\"\n");
+ if (parse_action_control_slash(&argc, &argv, &p.action,
+ &presult, true))
return -1;
- }
} else if (matches(*argv, "overhead") == 0) {
NEXT_ARG();
if (get_u16(&overhead, *argv, 10)) {
@@ -318,12 +293,13 @@ int print_police(struct action_util *a, FILE *f, struct rtattr *arg)
fprintf(f, "avrate %s ",
sprint_rate(rta_getattr_u32(tb[TCA_POLICE_AVRATE]),
b1));
- fprintf(f, "action %s", action_n2a(p->action));
+
+ print_action_control(f, "action ", p->action, "");
if (tb[TCA_POLICE_RESULT]) {
__u32 action = rta_getattr_u32(tb[TCA_POLICE_RESULT]);
- fprintf(f, "/%s ", action_n2a(action));
+ print_action_control(f, "/", action, " ");
} else
fprintf(f, " ");
diff --git a/tc/m_sample.c b/tc/m_sample.c
index 9291109..ff5ee6b 100644
--- a/tc/m_sample.c
+++ b/tc/m_sample.c
@@ -98,9 +98,7 @@ static int parse_sample(struct action_util *a, int *argc_p, char ***argv_p,
NEXT_ARG_FWD();
}
- p.action = TC_ACT_PIPE;
- if (argc && !action_a2n(*argv, &p.action, false))
- NEXT_ARG_FWD();
+ parse_action_control_dflt(&argc, &argv, &p.action, false, TC_ACT_PIPE);
if (argc) {
if (matches(*argv, "index") == 0) {
diff --git a/tc/m_simple.c b/tc/m_simple.c
index 3a8bd91..a4457c7 100644
--- a/tc/m_simple.c
+++ b/tc/m_simple.c
@@ -120,9 +120,6 @@ parse_simple(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
}
}
- if (argc && !action_a2n(*argv, &sel.action, false))
- NEXT_ARG_FWD();
-
if (argc) {
if (matches(*argv, "index") == 0) {
NEXT_ARG();
diff --git a/tc/m_skbedit.c b/tc/m_skbedit.c
index 638715f..aa374fc 100644
--- a/tc/m_skbedit.c
+++ b/tc/m_skbedit.c
@@ -120,9 +120,8 @@ parse_skbedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
argv++;
}
- sel.action = TC_ACT_PIPE;
- if (argc && !action_a2n(*argv, &sel.action, false))
- NEXT_ARG();
+ parse_action_control_dflt(&argc, &argv, &sel.action,
+ false, TC_ACT_PIPE);
if (argc) {
if (matches(*argv, "index") == 0) {
@@ -214,7 +213,7 @@ static int print_skbedit(struct action_util *au, FILE *f, struct rtattr *arg)
fprintf(f, " ptype %d", *ptype);
}
- fprintf(f, " %s", action_n2a(p->action));
+ print_action_control(f, " ", p->action, "");
fprintf(f, "\n\t index %u ref %d bind %d",
p->index, p->refcnt, p->bindcnt);
diff --git a/tc/m_skbmod.c b/tc/m_skbmod.c
index acb7771..1ccd474 100644
--- a/tc/m_skbmod.c
+++ b/tc/m_skbmod.c
@@ -61,7 +61,6 @@ static int parse_skbmod(struct action_util *a, int *argc_p, char ***argv_p,
char *saddr = NULL;
memset(&p, 0, sizeof(p));
- p.action = TC_ACT_PIPE; /* good default */
if (argc <= 0)
return -1;
@@ -123,31 +122,7 @@ static int parse_skbmod(struct action_util *a, int *argc_p, char ***argv_p,
argv++;
}
- if (argc) {
- if (matches(*argv, "reclassify") == 0) {
- p.action = TC_ACT_RECLASSIFY;
- argc--;
- argv++;
- } else if (matches(*argv, "pipe") == 0) {
- p.action = TC_ACT_PIPE;
- argc--;
- argv++;
- } else if (matches(*argv, "drop") == 0 ||
- matches(*argv, "shot") == 0) {
- p.action = TC_ACT_SHOT;
- argc--;
- argv++;
- } else if (matches(*argv, "continue") == 0) {
- p.action = TC_ACT_UNSPEC;
- argc--;
- argv++;
- } else if (matches(*argv, "pass") == 0 ||
- matches(*argv, "ok") == 0) {
- p.action = TC_ACT_OK;
- argc--;
- argv++;
- }
- }
+ parse_action_control_dflt(&argc, &argv, &p.action, false, TC_ACT_PIPE);
if (argc) {
if (matches(*argv, "index") == 0) {
@@ -206,7 +181,8 @@ static int print_skbmod(struct action_util *au, FILE *f, struct rtattr *arg)
p = RTA_DATA(tb[TCA_SKBMOD_PARMS]);
- fprintf(f, "skbmod action %s ", action_n2a(p->action));
+ fprintf(f, "skbmod ");
+ print_action_control(f, "", p->action, " ");
if (tb[TCA_SKBMOD_ETYPE]) {
skbmod_etype = rta_getattr_u16(tb[TCA_SKBMOD_ETYPE]);
diff --git a/tc/m_tunnel_key.c b/tc/m_tunnel_key.c
index 3ceec1c..fb418a7 100644
--- a/tc/m_tunnel_key.c
+++ b/tc/m_tunnel_key.c
@@ -77,7 +77,7 @@ static int tunnel_key_parse_dst_port(char *str, int type, struct nlmsghdr *n)
static int parse_tunnel_key(struct action_util *a, int *argc_p, char ***argv_p,
int tca_id, struct nlmsghdr *n)
{
- struct tc_tunnel_key parm = { .action = TC_ACT_PIPE };
+ struct tc_tunnel_key parm = {};
char **argv = *argv_p;
int argc = *argc_p;
struct rtattr *tail;
@@ -158,8 +158,8 @@ static int parse_tunnel_key(struct action_util *a, int *argc_p, char ***argv_p,
NEXT_ARG_FWD();
}
- if (argc && !action_a2n(*argv, &parm.action, false))
- NEXT_ARG_FWD();
+ parse_action_control_dflt(&argc, &argv, &parm.action,
+ false, TC_ACT_PIPE);
if (argc) {
if (matches(*argv, "index") == 0) {
@@ -265,7 +265,7 @@ static int print_tunnel_key(struct action_util *au, FILE *f, struct rtattr *arg)
tb[TCA_TUNNEL_KEY_ENC_DST_PORT]);
break;
}
- fprintf(f, " %s", action_n2a(parm->action));
+ print_action_control(f, " ", parm->action, "");
fprintf(f, "\n\tindex %d ref %d bind %d", parm->index, parm->refcnt,
parm->bindcnt);
diff --git a/tc/m_vlan.c b/tc/m_vlan.c
index 44b9375..2441b06 100644
--- a/tc/m_vlan.c
+++ b/tc/m_vlan.c
@@ -59,7 +59,7 @@ static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p,
int proto_set = 0;
__u8 prio;
int prio_set = 0;
- struct tc_vlan parm = { 0 };
+ struct tc_vlan parm = {};
if (matches(*argv, "vlan") != 0)
return -1;
@@ -133,9 +133,8 @@ static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p,
argv++;
}
- parm.action = TC_ACT_PIPE;
- if (argc && !action_a2n(*argv, &parm.action, false))
- NEXT_ARG_FWD();
+ parse_action_control_dflt(&argc, &argv, &parm.action,
+ false, TC_ACT_PIPE);
if (argc) {
if (matches(*argv, "index") == 0) {
@@ -224,7 +223,7 @@ static int print_vlan(struct action_util *au, FILE *f, struct rtattr *arg)
}
break;
}
- fprintf(f, " %s", action_n2a(parm->action));
+ print_action_control(f, " ", parm->action, "");
fprintf(f, "\n\t index %u ref %d bind %d", parm->index, parm->refcnt,
parm->bindcnt);
diff --git a/tc/tc_util.c b/tc/tc_util.c
index 24ca1f1..fd543c5 100644
--- a/tc/tc_util.c
+++ b/tc/tc_util.c
@@ -411,7 +411,7 @@ char *sprint_qdisc_handle(__u32 h, char *buf)
return buf;
}
-const char *action_n2a(int action)
+static const char *action_n2a(int action)
{
static char buf[64];
@@ -444,7 +444,7 @@ const char *action_n2a(int action)
*
* In error case, returns -1 and does not touch @result. Otherwise returns 0.
*/
-int action_a2n(char *arg, int *result, bool allow_num)
+static int action_a2n(char *arg, int *result, bool allow_num)
{
int n;
char dummy;
@@ -475,6 +475,139 @@ int action_a2n(char *arg, int *result, bool allow_num)
return 0;
}
+/* Parse action control including possible options.
+ *
+ * Parameters:
+ * @argc_p - pointer to argc to parse
+ * @argv_p - pointer to argv to parse
+ * @result_p - pointer to output variable
+ * @allow_num - whether action may be in numeric format already
+ *
+ * In error case, returns -1 and does not touch @result_1p. Otherwise returns 0.
+ */
+int parse_action_control(int *argc_p, char ***argv_p,
+ int *result_p, bool allow_num)
+{
+ int argc = *argc_p;
+ char **argv = *argv_p;
+ int result;
+
+ if (!argc)
+ return -1;
+ if (action_a2n(*argv, &result, allow_num) == -1) {
+ fprintf(stderr, "Bad action type %s\n", *argv);
+ return -1;
+ }
+ NEXT_ARG_FWD();
+ *argc_p = argc;
+ *argv_p = argv;
+ *result_p = result;
+ return 0;
+}
+
+/* Parse action control including possible options.
+ *
+ * Parameters:
+ * @argc_p - pointer to argc to parse
+ * @argv_p - pointer to argv to parse
+ * @result_p - pointer to output variable
+ * @allow_num - whether action may be in numeric format already
+ * @default_result - set as a result in case of parsing error
+ *
+ * In case there is an error during parsing, the default result is used.
+ */
+void parse_action_control_dflt(int *argc_p, char ***argv_p,
+ int *result_p, bool allow_num,
+ int default_result)
+{
+ if (parse_action_control(argc_p, argv_p, result_p, allow_num))
+ *result_p = default_result;
+}
+
+static int parse_action_control_slash_spaces(int *argc_p, char ***argv_p,
+ int *result1_p, int *result2_p,
+ bool allow_num)
+{
+ int argc = *argc_p;
+ char **argv = *argv_p;
+ int result1, result2;
+ int *result_p = &result1;
+ int ok = 0;
+ int ret;
+
+ while (argc > 0) {
+ switch (ok) {
+ case 1:
+ if (strcmp(*argv, "/") != 0)
+ goto out;
+ result_p = &result2;
+ NEXT_ARG();
+ /* fall-through */
+ case 0: /* fall-through */
+ case 2:
+ ret = parse_action_control(&argc, &argv,
+ result_p, allow_num);
+ if (ret)
+ return ret;
+ ok++;
+ break;
+ default:
+ goto out;
+ }
+ }
+out:
+ *result1_p = result1;
+ if (ok == 2)
+ *result2_p = result2;
+ *argc_p = argc;
+ *argv_p = argv;
+ return 0;
+}
+
+/* Parse action control with slash including possible options.
+ *
+ * Parameters:
+ * @argc_p - pointer to argc to parse
+ * @argv_p - pointer to argv to parse
+ * @result1_p - pointer to the first (before slash) output variable
+ * @result2_p - pointer to the second (after slash) output variable
+ * @allow_num - whether action may be in numeric format already
+ *
+ * In error case, returns -1 and does not touch @result*. Otherwise returns 0.
+ */
+int parse_action_control_slash(int *argc_p, char ***argv_p,
+ int *result1_p, int *result2_p, bool allow_num)
+{
+ char **argv = *argv_p;
+ int result1, result2;
+ char *p = strchr(*argv, '/');
+
+ if (!p)
+ return parse_action_control_slash_spaces(argc_p, argv_p,
+ result1_p, result2_p,
+ allow_num);
+ *p = 0;
+ if (action_a2n(*argv, &result1, allow_num)) {
+ if (p)
+ *p = '/';
+ return -1;
+ }
+
+ *p = '/';
+ if (action_a2n(p + 1, &result2, allow_num))
+ return -1;
+
+ *result1_p = result1;
+ *result2_p = result2;
+ return 0;
+}
+
+void print_action_control(FILE *f, const char *prefix,
+ int action, const char *suffix)
+{
+ fprintf(f, "%s%s%s", prefix, action_n2a(action), suffix);
+}
+
int get_linklayer(unsigned int *val, const char *arg)
{
int res;
diff --git a/tc/tc_util.h b/tc/tc_util.h
index 4db26c6..5c54ad3 100644
--- a/tc/tc_util.h
+++ b/tc/tc_util.h
@@ -100,8 +100,15 @@ char *sprint_tc_classid(__u32 h, char *buf);
int tc_print_police(FILE *f, struct rtattr *tb);
int parse_police(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n);
-const char *action_n2a(int action);
-int action_a2n(char *arg, int *result, bool allow_num);
+int parse_action_control(int *argc_p, char ***argv_p,
+ int *result_p, bool allow_num);
+void parse_action_control_dflt(int *argc_p, char ***argv_p,
+ int *result_p, bool allow_num,
+ int default_result);
+int parse_action_control_slash(int *argc_p, char ***argv_p,
+ int *result1_p, int *result2_p, bool allow_num);
+void print_action_control(FILE *f, const char *prefix,
+ int action, const char *suffix);
int act_parse_police(struct action_util *a, int *argc_p,
char ***argv_p, int tca_id, struct nlmsghdr *n);
int print_police(struct action_util *a, FILE *f, struct rtattr *tb);
--
2.9.3
^ permalink raw reply related
* [patch iproute2 v2 repost 3/3] tc/actions: introduce support for goto chain action
From: Jiri Pirko @ 2017-05-16 17:29 UTC (permalink / raw)
To: netdev
Cc: davem, jhs, xiyou.wangcong, dsa, edumazet, stephen, daniel,
alexander.h.duyck, simon.horman, mlxsw
In-Reply-To: <20170516172802.1317-1-jiri@resnulli.us>
From: Jiri Pirko <jiri@mellanox.com>
Allow user to set control action "goto" with filter chain index as
a parameter.
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
include/linux/pkt_cls.h | 16 +++++++++++++++-
man/man8/tc-ife.8 | 2 +-
man/man8/tc-pedit.8 | 2 +-
man/man8/tc-police.8 | 2 +-
man/man8/tc-vlan.8 | 2 +-
tc/m_connmark.c | 3 ++-
tc/m_gact.c | 6 ++++--
tc/m_pedit.c | 3 ++-
tc/m_police.c | 6 ++++--
tc/m_skbmod.c | 3 ++-
tc/m_vlan.c | 3 ++-
tc/tc_util.c | 24 +++++++++++++++++++++++-
12 files changed, 58 insertions(+), 14 deletions(-)
diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h
index f1129e3..1b9aa9e 100644
--- a/include/linux/pkt_cls.h
+++ b/include/linux/pkt_cls.h
@@ -37,7 +37,21 @@ enum {
#define TC_ACT_QUEUED 5
#define TC_ACT_REPEAT 6
#define TC_ACT_REDIRECT 7
-#define TC_ACT_JUMP 0x10000000
+
+/* There is a special kind of actions called "extended actions",
+ * which need a value parameter. These have a local opcode located in
+ * the highest nibble, starting from 1. The rest of the bits
+ * are used to carry the value. These two parts together make
+ * a combined opcode.
+ */
+#define __TC_ACT_EXT_SHIFT 28
+#define __TC_ACT_EXT(local) ((local) << __TC_ACT_EXT_SHIFT)
+#define TC_ACT_EXT_VAL_MASK ((1 << __TC_ACT_EXT_SHIFT) - 1)
+#define TC_ACT_EXT_CMP(combined, opcode) \
+ (((combined) & (~TC_ACT_EXT_VAL_MASK)) == opcode)
+
+#define TC_ACT_JUMP __TC_ACT_EXT(1)
+#define TC_ACT_GOTO_CHAIN __TC_ACT_EXT(2)
/* Action type identifiers*/
enum {
diff --git a/man/man8/tc-ife.8 b/man/man8/tc-ife.8
index a8f1f28..24595cc 100644
--- a/man/man8/tc-ife.8
+++ b/man/man8/tc-ife.8
@@ -34,7 +34,7 @@ IFE - encapsulate/decapsulate metadata
.ti -8
.IR CONTROL " := { "
-.BR reclassify " | " use " | " pipe " | " drop " | " continue " | " ok " }"
+.BR reclassify " | " use " | " pipe " | " drop " | " continue " | " ok " | " goto " " chain " " CHAIN_INDEX " }"
.SH DESCRIPTION
The
.B ife
diff --git a/man/man8/tc-pedit.8 b/man/man8/tc-pedit.8
index 7f482ea..de0d9e9 100644
--- a/man/man8/tc-pedit.8
+++ b/man/man8/tc-pedit.8
@@ -74,7 +74,7 @@ pedit - generic packet editor action
.ti -8
.IR CONTROL " := {"
-.BR reclassify " | " pipe " | " drop " | " shot " | " continue " | " pass " }"
+.BR reclassify " | " pipe " | " drop " | " shot " | " continue " | " pass " | " goto " " chain " " CHAIN_INDEX " }"
.SH DESCRIPTION
The
.B pedit
diff --git a/man/man8/tc-police.8 b/man/man8/tc-police.8
index 620c288..bcc5f43 100644
--- a/man/man8/tc-police.8
+++ b/man/man8/tc-police.8
@@ -30,7 +30,7 @@ police - policing action
.ti -8
.IR EXCEEDACT/NOTEXCEEDACT " := { "
-.BR pipe " | " ok " | " reclassify " | " drop " | " continue " }"
+.BR pipe " | " ok " | " reclassify " | " drop " | " continue " | " goto " " chain " " CHAIN_INDEX " }"
.SH DESCRIPTION
The
.B police
diff --git a/man/man8/tc-vlan.8 b/man/man8/tc-vlan.8
index af3de1c..59c81e8 100644
--- a/man/man8/tc-vlan.8
+++ b/man/man8/tc-vlan.8
@@ -26,7 +26,7 @@ vlan - vlan manipulation module
.ti -8
.IR CONTROL " := { "
-.BR reclassify " | " pipe " | " drop " | " continue " | " pass " }"
+.BR reclassify " | " pipe " | " drop " | " continue " | " pass " | " goto " " chain " " CHAIN_INDEX " }"
.SH DESCRIPTION
The
.B vlan
diff --git a/tc/m_connmark.c b/tc/m_connmark.c
index 3c2274b..37d7185 100644
--- a/tc/m_connmark.c
+++ b/tc/m_connmark.c
@@ -30,7 +30,8 @@ explain(void)
fprintf(stderr, "Usage: ... connmark [zone ZONE] [CONTROL] [index <INDEX>]\n");
fprintf(stderr, "where :\n"
"\tZONE is the conntrack zone\n"
- "\tCONTROL := reclassify|pipe|drop|continue|ok\n");
+ "\tCONTROL := reclassify | pipe | drop | continue | ok |\n"
+ "\t goto chain <CHAIN_INDEX>\n");
}
static void
diff --git a/tc/m_gact.c b/tc/m_gact.c
index 938b6b5..d95aa11 100644
--- a/tc/m_gact.c
+++ b/tc/m_gact.c
@@ -45,7 +45,8 @@ explain(void)
#ifdef CONFIG_GACT_PROB
fprintf(stderr, "Usage: ... gact <ACTION> [RAND] [INDEX]\n");
fprintf(stderr,
- "Where: \tACTION := reclassify | drop | continue | pass | pipe\n"
+ "Where: \tACTION := reclassify | drop | continue | pass | pipe |\n"
+ " \t goto chain <CHAIN_INDEX>\n"
"\tRAND := random <RANDTYPE> <ACTION> <VAL>\n"
"\tRANDTYPE := netrand | determ\n"
"\tVAL : = value not exceeding 10000\n"
@@ -54,7 +55,8 @@ explain(void)
#else
fprintf(stderr, "Usage: ... gact <ACTION> [INDEX]\n");
fprintf(stderr,
- "Where: \tACTION := reclassify | drop | continue | pass | pipe\n"
+ "Where: \tACTION := reclassify | drop | continue | pass | pipe |\n"
+ " \t goto chain <CHAIN_INDEX>\n"
"\tINDEX := index value used\n"
"\n");
#endif
diff --git a/tc/m_pedit.c b/tc/m_pedit.c
index 730a434..cb3bb0e 100644
--- a/tc/m_pedit.c
+++ b/tc/m_pedit.c
@@ -45,7 +45,8 @@ static void explain(void)
"\t\tCMD:= clear | invert | set <setval>| add <addval> | retain\n"
"\t<LAYERED>:= ip <ipdata> | ip6 <ip6data>\n"
" \t\t| udp <udpdata> | tcp <tcpdata> | icmp <icmpdata>\n"
- "\tCONTROL:= reclassify | pipe | drop | continue | pass\n"
+ "\tCONTROL:= reclassify | pipe | drop | continue | pass |\n"
+ "\t goto chain <CHAIN_INDEX>\n"
"\tNOTE: if 'ex' is set, extended functionality will be supported (kernel >= 4.11)\n"
"For Example usage look at the examples directory\n");
diff --git a/tc/m_police.c b/tc/m_police.c
index 2b73969..86117db 100644
--- a/tc/m_police.c
+++ b/tc/m_police.c
@@ -41,7 +41,8 @@ static void usage(void)
fprintf(stderr, "Where: CONTROL := conform-exceed <EXCEEDACT>[/NOTEXCEEDACT]\n");
fprintf(stderr, " Define how to handle packets which exceed (<EXCEEDACT>)\n");
fprintf(stderr, " or conform (<NOTEXCEEDACT>) the configured bandwidth limit.\n");
- fprintf(stderr, " EXCEEDACT/NOTEXCEEDACT := { pipe | ok | reclassify | drop | continue }\n");
+ fprintf(stderr, " EXCEEDACT/NOTEXCEEDACT := { pipe | ok | reclassify | drop | continue |\n");
+ fprintf(stderr, " goto chain <CHAIN_INDEX> }\n");
exit(-1);
}
@@ -150,7 +151,8 @@ int act_parse_police(struct action_util *a, int *argc_p, char ***argv_p,
matches(*argv, "shot") == 0 ||
matches(*argv, "continue") == 0 ||
matches(*argv, "pass") == 0 ||
- matches(*argv, "pipe") == 0) {
+ matches(*argv, "pipe") == 0 ||
+ matches(*argv, "goto") == 0) {
if (parse_action_control(&argc, &argv, &p.action, false))
return -1;
} else if (strcmp(*argv, "conform-exceed") == 0) {
diff --git a/tc/m_skbmod.c b/tc/m_skbmod.c
index 1ccd474..ba79308 100644
--- a/tc/m_skbmod.c
+++ b/tc/m_skbmod.c
@@ -36,7 +36,8 @@ static void skbmod_explain(void)
"\tDMAC := 6 byte Destination MAC address\n"
"\tSMAC := optional 6 byte Source MAC address\n"
"\tETYPE := optional 16 bit ethertype\n"
- "\tCONTROL := reclassify|pipe|drop|continue|ok\n"
+ "\tCONTROL := reclassify | pipe | drop | continue | ok |\n"
+ "\t goto chain <CHAIN_INDEX>\n"
"\tINDEX := skbmod index value to use\n");
}
diff --git a/tc/m_vlan.c b/tc/m_vlan.c
index 2441b06..cccb499 100644
--- a/tc/m_vlan.c
+++ b/tc/m_vlan.c
@@ -32,7 +32,8 @@ static void explain(void)
fprintf(stderr, " vlan modify [ protocol VLANPROTO ] id VLANID [ priority VLANPRIO ] [CONTROL]\n");
fprintf(stderr, " VLANPROTO is one of 802.1Q or 802.1AD\n");
fprintf(stderr, " with default: 802.1Q\n");
- fprintf(stderr, " CONTROL := reclassify | pipe | drop | continue | pass\n");
+ fprintf(stderr, " CONTROL := reclassify | pipe | drop | continue | pass |\n");
+ fprintf(stderr, " goto chain <CHAIN_INDEX>\n");
}
static void usage(void)
diff --git a/tc/tc_util.c b/tc/tc_util.c
index fd543c5..4f7283d 100644
--- a/tc/tc_util.c
+++ b/tc/tc_util.c
@@ -415,6 +415,8 @@ static const char *action_n2a(int action)
{
static char buf[64];
+ if (TC_ACT_EXT_CMP(action, TC_ACT_GOTO_CHAIN))
+ return "goto";
switch (action) {
case TC_ACT_UNSPEC:
return "continue";
@@ -459,6 +461,7 @@ static int action_a2n(char *arg, int *result, bool allow_num)
{"ok", TC_ACT_OK},
{"reclassify", TC_ACT_RECLASSIFY},
{"pipe", TC_ACT_PIPE},
+ {"goto", TC_ACT_GOTO_CHAIN},
{ NULL },
}, *iter;
@@ -498,6 +501,22 @@ int parse_action_control(int *argc_p, char ***argv_p,
fprintf(stderr, "Bad action type %s\n", *argv);
return -1;
}
+ if (result == TC_ACT_GOTO_CHAIN) {
+ __u32 chain_index;
+
+ NEXT_ARG();
+ if (matches(*argv, "chain") != 0) {
+ fprintf(stderr, "\"chain index\" expected\n");
+ return -1;
+ }
+ NEXT_ARG();
+ if (get_u32(&chain_index, *argv, 10) ||
+ chain_index > TC_ACT_EXT_VAL_MASK) {
+ fprintf(stderr, "Illegal \"chain index\"\n");
+ return -1;
+ }
+ result |= chain_index;
+ }
NEXT_ARG_FWD();
*argc_p = argc;
*argv_p = argv;
@@ -605,7 +624,10 @@ int parse_action_control_slash(int *argc_p, char ***argv_p,
void print_action_control(FILE *f, const char *prefix,
int action, const char *suffix)
{
- fprintf(f, "%s%s%s", prefix, action_n2a(action), suffix);
+ fprintf(f, "%s%s", prefix, action_n2a(action));
+ if (TC_ACT_EXT_CMP(action, TC_ACT_GOTO_CHAIN))
+ fprintf(f, " chain %u", action & TC_ACT_EXT_VAL_MASK);
+ fprintf(f, "%s", suffix);
}
int get_linklayer(unsigned int *val, const char *arg)
--
2.9.3
^ permalink raw reply related
* Re: [PATCH] net/smc: mark as BROKEN due to remote memory exposure
From: David Miller @ 2017-05-16 17:36 UTC (permalink / raw)
To: dledford-H+wXaHxf7aLQT0dZR+AlfA
Cc: Bart.VanAssche-XdAiOPVOjttBDgjK7y7TUQ,
torvalds-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b, hch-jcswGhMUV9g,
netdev-u79uwXL29TY76Z2rM5mHXA, linux-rdma-u79uwXL29TY76Z2rM5mHXA,
stable-u79uwXL29TY76Z2rM5mHXA,
ubraun-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8
In-Reply-To: <1494955244.3259.130.camel-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
From: Doug Ledford <dledford-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Date: Tue, 16 May 2017 13:20:44 -0400
> Anyway, we're just talking out what happened, when what we really need
> to focus on is moving forward. Again, your thoughts on marking SMC
> EXPERIMENTAL until it's fixed up and unfreezing the API in case we need
> to adjust it to work on different link layers?
Something like:
http://patchwork.ozlabs.org/patch/762803/
with the addition of the EXPERIMENTAL dependency?
Sure.
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [patch net-next 00/12] mlxsw: Preparations for restructuring
From: Jiri Pirko @ 2017-05-16 17:38 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, mlxsw
From: Jiri Pirko <jiri@mellanox.com>
This patchset doesn't introduce any functional changes and merely meant
to make the code base more receptive for upcoming restructuring.
The first six patches mainly shuffle code in order to reduce the scope of
structs that shouldn't be defined in the main driver header. Most of them
will be later expanded, so it makes sense to correctly place them now.
The last patches mostly simplify bridge-related functions, so that they
could be more easily modified later on.
Ido Schimmel (12):
mlxsw: spectrum_buffer: Reduce scope of shared buffer struct
mlxsw: spectrum_router: Reduce scope of router struct
mlxsw: spectrum_switchdev: Reduce scope of bridge struct
mlxsw: spectrum_router: Move RIFs array to its rightful place
mlxsw: spectrum_router: Move FIB notification block to router struct
mlxsw: spectrum_router: Initialize RIFs in a separate function
mlxsw: spectrum_switchdev: Remove redundant check
mlxsw: spectrum_switchdev: Don't batch VLAN operations
mlxsw: spectrum_switchdev: Don't batch STP operations
mlxsw: spectrum_switchdev: Don't batch learning operations
mlxsw: spectrum: Move PVID code to appropriate place
mlxsw: spectrum: Default ports to non-virtual mode
drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 118 +++++-
drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 131 +------
.../net/ethernet/mellanox/mlxsw/spectrum_buffers.c | 73 +++-
.../net/ethernet/mellanox/mlxsw/spectrum_dpipe.c | 17 +-
.../net/ethernet/mellanox/mlxsw/spectrum_router.c | 289 +++++++++-----
.../net/ethernet/mellanox/mlxsw/spectrum_router.h | 2 +
.../ethernet/mellanox/mlxsw/spectrum_switchdev.c | 415 ++++++++-------------
7 files changed, 529 insertions(+), 516 deletions(-)
--
2.9.3
^ permalink raw reply
* [patch net-next 01/12] mlxsw: spectrum_buffer: Reduce scope of shared buffer struct
From: Jiri Pirko @ 2017-05-16 17:38 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, mlxsw
In-Reply-To: <20170516173835.2978-1-jiri@resnulli.us>
From: Ido Schimmel <idosch@mellanox.com>
The shared buffer structure ('mlxsw_sp_sb') doesn't need to be
accessible to anyone, but the shared buffer code located at
spectrum_buffers.c
Make this apparent and reduce its scope by defining it there.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 54 ++--------------
.../net/ethernet/mellanox/mlxsw/spectrum_buffers.c | 73 +++++++++++++++++++---
2 files changed, 68 insertions(+), 59 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
index 0c23bc1..976f5b6 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@ -110,43 +110,6 @@ static inline bool mlxsw_sp_fid_is_vfid(u16 fid)
return fid >= MLXSW_SP_VFID_BASE && fid < MLXSW_SP_DUMMY_FID;
}
-struct mlxsw_sp_sb_pr {
- enum mlxsw_reg_sbpr_mode mode;
- u32 size;
-};
-
-struct mlxsw_cp_sb_occ {
- u32 cur;
- u32 max;
-};
-
-struct mlxsw_sp_sb_cm {
- u32 min_buff;
- u32 max_buff;
- u8 pool;
- struct mlxsw_cp_sb_occ occ;
-};
-
-struct mlxsw_sp_sb_pm {
- u32 min_buff;
- u32 max_buff;
- struct mlxsw_cp_sb_occ occ;
-};
-
-#define MLXSW_SP_SB_POOL_COUNT 4
-#define MLXSW_SP_SB_TC_COUNT 8
-
-struct mlxsw_sp_sb_port {
- struct mlxsw_sp_sb_cm cms[2][MLXSW_SP_SB_TC_COUNT];
- struct mlxsw_sp_sb_pm pms[2][MLXSW_SP_SB_POOL_COUNT];
-};
-
-struct mlxsw_sp_sb {
- struct mlxsw_sp_sb_pr prs[2][MLXSW_SP_SB_POOL_COUNT];
- struct mlxsw_sp_sb_port *ports;
- u32 cell_size;
-};
-
#define MLXSW_SP_PREFIX_COUNT (sizeof(struct in6_addr) * BITS_PER_BYTE)
struct mlxsw_sp_prefix_usage {
@@ -231,6 +194,7 @@ struct mlxsw_sp_router {
bool aborted;
};
+struct mlxsw_sp_sb;
struct mlxsw_sp_acl;
struct mlxsw_sp_counter_pool;
@@ -261,7 +225,7 @@ struct mlxsw_sp {
struct mlxsw_sp_upper master_bridge;
struct mlxsw_sp_upper *lags;
u8 *port_to_module;
- struct mlxsw_sp_sb sb;
+ struct mlxsw_sp_sb *sb;
struct mlxsw_sp_router router;
struct mlxsw_sp_acl *acl;
struct {
@@ -282,18 +246,6 @@ mlxsw_sp_lag_get(struct mlxsw_sp *mlxsw_sp, u16 lag_id)
return &mlxsw_sp->lags[lag_id];
}
-static inline u32 mlxsw_sp_cells_bytes(const struct mlxsw_sp *mlxsw_sp,
- u32 cells)
-{
- return mlxsw_sp->sb.cell_size * cells;
-}
-
-static inline u32 mlxsw_sp_bytes_cells(const struct mlxsw_sp *mlxsw_sp,
- u32 bytes)
-{
- return DIV_ROUND_UP(bytes, mlxsw_sp->sb.cell_size);
-}
-
struct mlxsw_sp_port_pcpu_stats {
u64 rx_packets;
u64 rx_bytes;
@@ -515,6 +467,8 @@ int mlxsw_sp_sb_occ_tc_port_bind_get(struct mlxsw_core_port *mlxsw_core_port,
unsigned int sb_index, u16 tc_index,
enum devlink_sb_pool_type pool_type,
u32 *p_cur, u32 *p_max);
+u32 mlxsw_sp_cells_bytes(const struct mlxsw_sp *mlxsw_sp, u32 cells);
+u32 mlxsw_sp_bytes_cells(const struct mlxsw_sp *mlxsw_sp, u32 bytes);
int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp);
void mlxsw_sp_switchdev_fini(struct mlxsw_sp *mlxsw_sp);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c
index 997189c..93728c6 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c
@@ -43,25 +43,72 @@
#include "port.h"
#include "reg.h"
+struct mlxsw_sp_sb_pr {
+ enum mlxsw_reg_sbpr_mode mode;
+ u32 size;
+};
+
+struct mlxsw_cp_sb_occ {
+ u32 cur;
+ u32 max;
+};
+
+struct mlxsw_sp_sb_cm {
+ u32 min_buff;
+ u32 max_buff;
+ u8 pool;
+ struct mlxsw_cp_sb_occ occ;
+};
+
+struct mlxsw_sp_sb_pm {
+ u32 min_buff;
+ u32 max_buff;
+ struct mlxsw_cp_sb_occ occ;
+};
+
+#define MLXSW_SP_SB_POOL_COUNT 4
+#define MLXSW_SP_SB_TC_COUNT 8
+
+struct mlxsw_sp_sb_port {
+ struct mlxsw_sp_sb_cm cms[2][MLXSW_SP_SB_TC_COUNT];
+ struct mlxsw_sp_sb_pm pms[2][MLXSW_SP_SB_POOL_COUNT];
+};
+
+struct mlxsw_sp_sb {
+ struct mlxsw_sp_sb_pr prs[2][MLXSW_SP_SB_POOL_COUNT];
+ struct mlxsw_sp_sb_port *ports;
+ u32 cell_size;
+};
+
+u32 mlxsw_sp_cells_bytes(const struct mlxsw_sp *mlxsw_sp, u32 cells)
+{
+ return mlxsw_sp->sb->cell_size * cells;
+}
+
+u32 mlxsw_sp_bytes_cells(const struct mlxsw_sp *mlxsw_sp, u32 bytes)
+{
+ return DIV_ROUND_UP(bytes, mlxsw_sp->sb->cell_size);
+}
+
static struct mlxsw_sp_sb_pr *mlxsw_sp_sb_pr_get(struct mlxsw_sp *mlxsw_sp,
u8 pool,
enum mlxsw_reg_sbxx_dir dir)
{
- return &mlxsw_sp->sb.prs[dir][pool];
+ return &mlxsw_sp->sb->prs[dir][pool];
}
static struct mlxsw_sp_sb_cm *mlxsw_sp_sb_cm_get(struct mlxsw_sp *mlxsw_sp,
u8 local_port, u8 pg_buff,
enum mlxsw_reg_sbxx_dir dir)
{
- return &mlxsw_sp->sb.ports[local_port].cms[dir][pg_buff];
+ return &mlxsw_sp->sb->ports[local_port].cms[dir][pg_buff];
}
static struct mlxsw_sp_sb_pm *mlxsw_sp_sb_pm_get(struct mlxsw_sp *mlxsw_sp,
u8 local_port, u8 pool,
enum mlxsw_reg_sbxx_dir dir)
{
- return &mlxsw_sp->sb.ports[local_port].pms[dir][pool];
+ return &mlxsw_sp->sb->ports[local_port].pms[dir][pool];
}
static int mlxsw_sp_sb_pr_write(struct mlxsw_sp *mlxsw_sp, u8 pool,
@@ -215,16 +262,17 @@ static int mlxsw_sp_sb_ports_init(struct mlxsw_sp *mlxsw_sp)
{
unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
- mlxsw_sp->sb.ports = kcalloc(max_ports, sizeof(struct mlxsw_sp_sb_port),
- GFP_KERNEL);
- if (!mlxsw_sp->sb.ports)
+ mlxsw_sp->sb->ports = kcalloc(max_ports,
+ sizeof(struct mlxsw_sp_sb_port),
+ GFP_KERNEL);
+ if (!mlxsw_sp->sb->ports)
return -ENOMEM;
return 0;
}
static void mlxsw_sp_sb_ports_fini(struct mlxsw_sp *mlxsw_sp)
{
- kfree(mlxsw_sp->sb.ports);
+ kfree(mlxsw_sp->sb->ports);
}
#define MLXSW_SP_SB_PR_INGRESS_SIZE 12440000
@@ -551,15 +599,19 @@ int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp)
if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, CELL_SIZE))
return -EIO;
- mlxsw_sp->sb.cell_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, CELL_SIZE);
if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MAX_BUFFER_SIZE))
return -EIO;
sb_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_BUFFER_SIZE);
+ mlxsw_sp->sb = kzalloc(sizeof(*mlxsw_sp->sb), GFP_KERNEL);
+ if (!mlxsw_sp->sb)
+ return -ENOMEM;
+ mlxsw_sp->sb->cell_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, CELL_SIZE);
+
err = mlxsw_sp_sb_ports_init(mlxsw_sp);
if (err)
- return err;
+ goto err_sb_ports_init;
err = mlxsw_sp_sb_prs_init(mlxsw_sp);
if (err)
goto err_sb_prs_init;
@@ -584,6 +636,8 @@ int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp)
err_sb_cpu_port_sb_cms_init:
err_sb_prs_init:
mlxsw_sp_sb_ports_fini(mlxsw_sp);
+err_sb_ports_init:
+ kfree(mlxsw_sp->sb);
return err;
}
@@ -591,6 +645,7 @@ void mlxsw_sp_buffers_fini(struct mlxsw_sp *mlxsw_sp)
{
devlink_sb_unregister(priv_to_devlink(mlxsw_sp->core), 0);
mlxsw_sp_sb_ports_fini(mlxsw_sp);
+ kfree(mlxsw_sp->sb);
}
int mlxsw_sp_port_buffers_init(struct mlxsw_sp_port *mlxsw_sp_port)
--
2.9.3
^ permalink raw reply related
* [patch net-next 02/12] mlxsw: spectrum_router: Reduce scope of router struct
From: Jiri Pirko @ 2017-05-16 17:38 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, mlxsw
In-Reply-To: <20170516173835.2978-1-jiri@resnulli.us>
From: Ido Schimmel <idosch@mellanox.com>
In a similar fashion to previous patch, the router structure
('mlxsw_sp_router') doesn't need to be accessible to anyone, but the
router code located at spectrum_router.c
Make this apparent and reduce its scope by defining it there.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 49 +-----
.../net/ethernet/mellanox/mlxsw/spectrum_router.c | 195 ++++++++++++++-------
2 files changed, 130 insertions(+), 114 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
index 976f5b6..2eb2230 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@ -110,33 +110,6 @@ static inline bool mlxsw_sp_fid_is_vfid(u16 fid)
return fid >= MLXSW_SP_VFID_BASE && fid < MLXSW_SP_DUMMY_FID;
}
-#define MLXSW_SP_PREFIX_COUNT (sizeof(struct in6_addr) * BITS_PER_BYTE)
-
-struct mlxsw_sp_prefix_usage {
- DECLARE_BITMAP(b, MLXSW_SP_PREFIX_COUNT);
-};
-
-enum mlxsw_sp_l3proto {
- MLXSW_SP_L3_PROTO_IPV4,
- MLXSW_SP_L3_PROTO_IPV6,
-};
-
-struct mlxsw_sp_lpm_tree {
- u8 id; /* tree ID */
- unsigned int ref_count;
- enum mlxsw_sp_l3proto proto;
- struct mlxsw_sp_prefix_usage prefix_usage;
-};
-
-struct mlxsw_sp_fib;
-
-struct mlxsw_sp_vr {
- u16 id; /* virtual router ID */
- u32 tb_id; /* kernel fib table id */
- unsigned int rif_count;
- struct mlxsw_sp_fib *fib4;
-};
-
enum mlxsw_sp_span_type {
MLXSW_SP_SPAN_EGRESS,
MLXSW_SP_SPAN_INGRESS
@@ -175,26 +148,8 @@ struct mlxsw_sp_port_mall_tc_entry {
};
};
-struct mlxsw_sp_router {
- struct mlxsw_sp_vr *vrs;
- struct rhashtable neigh_ht;
- struct rhashtable nexthop_group_ht;
- struct rhashtable nexthop_ht;
- struct {
- struct mlxsw_sp_lpm_tree *trees;
- unsigned int tree_count;
- } lpm;
- struct {
- struct delayed_work dw;
- unsigned long interval; /* ms */
- } neighs_update;
- struct delayed_work nexthop_probe_dw;
-#define MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL 5000 /* ms */
- struct list_head nexthop_neighs_list;
- bool aborted;
-};
-
struct mlxsw_sp_sb;
+struct mlxsw_sp_router;
struct mlxsw_sp_acl;
struct mlxsw_sp_counter_pool;
@@ -226,7 +181,7 @@ struct mlxsw_sp {
struct mlxsw_sp_upper *lags;
u8 *port_to_module;
struct mlxsw_sp_sb *sb;
- struct mlxsw_sp_router router;
+ struct mlxsw_sp_router *router;
struct mlxsw_sp_acl *acl;
struct {
DECLARE_BITMAP(usage, MLXSW_SP_KVD_LINEAR_SIZE);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index 33cec1c..28f7f54 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -56,6 +56,29 @@
#include "spectrum_dpipe.h"
#include "spectrum_router.h"
+struct mlxsw_sp_vr;
+struct mlxsw_sp_lpm_tree;
+
+struct mlxsw_sp_router {
+ struct mlxsw_sp *mlxsw_sp;
+ struct mlxsw_sp_vr *vrs;
+ struct rhashtable neigh_ht;
+ struct rhashtable nexthop_group_ht;
+ struct rhashtable nexthop_ht;
+ struct {
+ struct mlxsw_sp_lpm_tree *trees;
+ unsigned int tree_count;
+ } lpm;
+ struct {
+ struct delayed_work dw;
+ unsigned long interval; /* ms */
+ } neighs_update;
+ struct delayed_work nexthop_probe_dw;
+#define MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL 5000 /* ms */
+ struct list_head nexthop_neighs_list;
+ bool aborted;
+};
+
struct mlxsw_sp_rif {
struct list_head nexthop_list;
struct list_head neigh_list;
@@ -220,6 +243,12 @@ static struct mlxsw_sp_rif *
mlxsw_sp_rif_find_by_dev(const struct mlxsw_sp *mlxsw_sp,
const struct net_device *dev);
+#define MLXSW_SP_PREFIX_COUNT (sizeof(struct in6_addr) * BITS_PER_BYTE)
+
+struct mlxsw_sp_prefix_usage {
+ DECLARE_BITMAP(b, MLXSW_SP_PREFIX_COUNT);
+};
+
#define mlxsw_sp_prefix_usage_for_each(prefix, prefix_usage) \
for_each_set_bit(prefix, (prefix_usage)->b, MLXSW_SP_PREFIX_COUNT)
@@ -284,6 +313,7 @@ enum mlxsw_sp_fib_entry_type {
};
struct mlxsw_sp_nexthop_group;
+struct mlxsw_sp_fib;
struct mlxsw_sp_fib_node {
struct list_head entry_list;
@@ -310,6 +340,18 @@ struct mlxsw_sp_fib_entry {
bool offloaded;
};
+enum mlxsw_sp_l3proto {
+ MLXSW_SP_L3_PROTO_IPV4,
+ MLXSW_SP_L3_PROTO_IPV6,
+};
+
+struct mlxsw_sp_lpm_tree {
+ u8 id; /* tree ID */
+ unsigned int ref_count;
+ enum mlxsw_sp_l3proto proto;
+ struct mlxsw_sp_prefix_usage prefix_usage;
+};
+
struct mlxsw_sp_fib {
struct rhashtable ht;
struct list_head node_list;
@@ -320,6 +362,13 @@ struct mlxsw_sp_fib {
enum mlxsw_sp_l3proto proto;
};
+struct mlxsw_sp_vr {
+ u16 id; /* virtual router ID */
+ u32 tb_id; /* kernel fib table id */
+ unsigned int rif_count;
+ struct mlxsw_sp_fib *fib4;
+};
+
static const struct rhashtable_params mlxsw_sp_fib_ht_params;
static struct mlxsw_sp_fib *mlxsw_sp_fib_create(struct mlxsw_sp_vr *vr,
@@ -358,8 +407,8 @@ mlxsw_sp_lpm_tree_find_unused(struct mlxsw_sp *mlxsw_sp)
static struct mlxsw_sp_lpm_tree *lpm_tree;
int i;
- for (i = 0; i < mlxsw_sp->router.lpm.tree_count; i++) {
- lpm_tree = &mlxsw_sp->router.lpm.trees[i];
+ for (i = 0; i < mlxsw_sp->router->lpm.tree_count; i++) {
+ lpm_tree = &mlxsw_sp->router->lpm.trees[i];
if (lpm_tree->ref_count == 0)
return lpm_tree;
}
@@ -455,8 +504,8 @@ mlxsw_sp_lpm_tree_get(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_lpm_tree *lpm_tree;
int i;
- for (i = 0; i < mlxsw_sp->router.lpm.tree_count; i++) {
- lpm_tree = &mlxsw_sp->router.lpm.trees[i];
+ for (i = 0; i < mlxsw_sp->router->lpm.tree_count; i++) {
+ lpm_tree = &mlxsw_sp->router->lpm.trees[i];
if (lpm_tree->ref_count != 0 &&
lpm_tree->proto == proto &&
mlxsw_sp_prefix_usage_eq(&lpm_tree->prefix_usage,
@@ -493,15 +542,15 @@ static int mlxsw_sp_lpm_init(struct mlxsw_sp *mlxsw_sp)
return -EIO;
max_trees = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_LPM_TREES);
- mlxsw_sp->router.lpm.tree_count = max_trees - MLXSW_SP_LPM_TREE_MIN;
- mlxsw_sp->router.lpm.trees = kcalloc(mlxsw_sp->router.lpm.tree_count,
+ mlxsw_sp->router->lpm.tree_count = max_trees - MLXSW_SP_LPM_TREE_MIN;
+ mlxsw_sp->router->lpm.trees = kcalloc(mlxsw_sp->router->lpm.tree_count,
sizeof(struct mlxsw_sp_lpm_tree),
GFP_KERNEL);
- if (!mlxsw_sp->router.lpm.trees)
+ if (!mlxsw_sp->router->lpm.trees)
return -ENOMEM;
- for (i = 0; i < mlxsw_sp->router.lpm.tree_count; i++) {
- lpm_tree = &mlxsw_sp->router.lpm.trees[i];
+ for (i = 0; i < mlxsw_sp->router->lpm.tree_count; i++) {
+ lpm_tree = &mlxsw_sp->router->lpm.trees[i];
lpm_tree->id = i + MLXSW_SP_LPM_TREE_MIN;
}
@@ -510,7 +559,7 @@ static int mlxsw_sp_lpm_init(struct mlxsw_sp *mlxsw_sp)
static void mlxsw_sp_lpm_fini(struct mlxsw_sp *mlxsw_sp)
{
- kfree(mlxsw_sp->router.lpm.trees);
+ kfree(mlxsw_sp->router->lpm.trees);
}
static bool mlxsw_sp_vr_is_used(const struct mlxsw_sp_vr *vr)
@@ -524,7 +573,7 @@ static struct mlxsw_sp_vr *mlxsw_sp_vr_find_unused(struct mlxsw_sp *mlxsw_sp)
int i;
for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) {
- vr = &mlxsw_sp->router.vrs[i];
+ vr = &mlxsw_sp->router->vrs[i];
if (!mlxsw_sp_vr_is_used(vr))
return vr;
}
@@ -570,7 +619,7 @@ static struct mlxsw_sp_vr *mlxsw_sp_vr_find(struct mlxsw_sp *mlxsw_sp,
tb_id = mlxsw_sp_fix_tb_id(tb_id);
for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) {
- vr = &mlxsw_sp->router.vrs[i];
+ vr = &mlxsw_sp->router->vrs[i];
if (mlxsw_sp_vr_is_used(vr) && vr->tb_id == tb_id)
return vr;
}
@@ -677,13 +726,13 @@ static int mlxsw_sp_vrs_init(struct mlxsw_sp *mlxsw_sp)
return -EIO;
max_vrs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS);
- mlxsw_sp->router.vrs = kcalloc(max_vrs, sizeof(struct mlxsw_sp_vr),
- GFP_KERNEL);
- if (!mlxsw_sp->router.vrs)
+ mlxsw_sp->router->vrs = kcalloc(max_vrs, sizeof(struct mlxsw_sp_vr),
+ GFP_KERNEL);
+ if (!mlxsw_sp->router->vrs)
return -ENOMEM;
for (i = 0; i < max_vrs; i++) {
- vr = &mlxsw_sp->router.vrs[i];
+ vr = &mlxsw_sp->router->vrs[i];
vr->id = i;
}
@@ -703,7 +752,7 @@ static void mlxsw_sp_vrs_fini(struct mlxsw_sp *mlxsw_sp)
*/
mlxsw_core_flush_owq();
mlxsw_sp_router_fib_flush(mlxsw_sp);
- kfree(mlxsw_sp->router.vrs);
+ kfree(mlxsw_sp->router->vrs);
}
struct mlxsw_sp_neigh_key {
@@ -755,7 +804,7 @@ static int
mlxsw_sp_neigh_entry_insert(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_neigh_entry *neigh_entry)
{
- return rhashtable_insert_fast(&mlxsw_sp->router.neigh_ht,
+ return rhashtable_insert_fast(&mlxsw_sp->router->neigh_ht,
&neigh_entry->ht_node,
mlxsw_sp_neigh_ht_params);
}
@@ -764,7 +813,7 @@ static void
mlxsw_sp_neigh_entry_remove(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_neigh_entry *neigh_entry)
{
- rhashtable_remove_fast(&mlxsw_sp->router.neigh_ht,
+ rhashtable_remove_fast(&mlxsw_sp->router->neigh_ht,
&neigh_entry->ht_node,
mlxsw_sp_neigh_ht_params);
}
@@ -812,7 +861,7 @@ mlxsw_sp_neigh_entry_lookup(struct mlxsw_sp *mlxsw_sp, struct neighbour *n)
struct mlxsw_sp_neigh_key key;
key.n = n;
- return rhashtable_lookup_fast(&mlxsw_sp->router.neigh_ht,
+ return rhashtable_lookup_fast(&mlxsw_sp->router->neigh_ht,
&key, mlxsw_sp_neigh_ht_params);
}
@@ -821,7 +870,7 @@ mlxsw_sp_router_neighs_update_interval_init(struct mlxsw_sp *mlxsw_sp)
{
unsigned long interval = NEIGH_VAR(&arp_tbl.parms, DELAY_PROBE_TIME);
- mlxsw_sp->router.neighs_update.interval = jiffies_to_msecs(interval);
+ mlxsw_sp->router->neighs_update.interval = jiffies_to_msecs(interval);
}
static void mlxsw_sp_router_neigh_ent_ipv4_process(struct mlxsw_sp *mlxsw_sp,
@@ -951,7 +1000,7 @@ static void mlxsw_sp_router_neighs_update_nh(struct mlxsw_sp *mlxsw_sp)
/* Take RTNL mutex here to prevent lists from changes */
rtnl_lock();
- list_for_each_entry(neigh_entry, &mlxsw_sp->router.nexthop_neighs_list,
+ list_for_each_entry(neigh_entry, &mlxsw_sp->router->nexthop_neighs_list,
nexthop_neighs_list_node)
/* If this neigh have nexthops, make the kernel think this neigh
* is active regardless of the traffic.
@@ -963,33 +1012,35 @@ static void mlxsw_sp_router_neighs_update_nh(struct mlxsw_sp *mlxsw_sp)
static void
mlxsw_sp_router_neighs_update_work_schedule(struct mlxsw_sp *mlxsw_sp)
{
- unsigned long interval = mlxsw_sp->router.neighs_update.interval;
+ unsigned long interval = mlxsw_sp->router->neighs_update.interval;
- mlxsw_core_schedule_dw(&mlxsw_sp->router.neighs_update.dw,
+ mlxsw_core_schedule_dw(&mlxsw_sp->router->neighs_update.dw,
msecs_to_jiffies(interval));
}
static void mlxsw_sp_router_neighs_update_work(struct work_struct *work)
{
- struct mlxsw_sp *mlxsw_sp = container_of(work, struct mlxsw_sp,
- router.neighs_update.dw.work);
+ struct mlxsw_sp_router *router;
int err;
- err = mlxsw_sp_router_neighs_update_rauhtd(mlxsw_sp);
+ router = container_of(work, struct mlxsw_sp_router,
+ neighs_update.dw.work);
+ err = mlxsw_sp_router_neighs_update_rauhtd(router->mlxsw_sp);
if (err)
- dev_err(mlxsw_sp->bus_info->dev, "Could not update kernel for neigh activity");
+ dev_err(router->mlxsw_sp->bus_info->dev, "Could not update kernel for neigh activity");
- mlxsw_sp_router_neighs_update_nh(mlxsw_sp);
+ mlxsw_sp_router_neighs_update_nh(router->mlxsw_sp);
- mlxsw_sp_router_neighs_update_work_schedule(mlxsw_sp);
+ mlxsw_sp_router_neighs_update_work_schedule(router->mlxsw_sp);
}
static void mlxsw_sp_router_probe_unresolved_nexthops(struct work_struct *work)
{
struct mlxsw_sp_neigh_entry *neigh_entry;
- struct mlxsw_sp *mlxsw_sp = container_of(work, struct mlxsw_sp,
- router.nexthop_probe_dw.work);
+ struct mlxsw_sp_router *router;
+ router = container_of(work, struct mlxsw_sp_router,
+ nexthop_probe_dw.work);
/* Iterate over nexthop neighbours, find those who are unresolved and
* send arp on them. This solves the chicken-egg problem when
* the nexthop wouldn't get offloaded until the neighbor is resolved
@@ -999,13 +1050,13 @@ static void mlxsw_sp_router_probe_unresolved_nexthops(struct work_struct *work)
* Take RTNL mutex here to prevent lists from changes.
*/
rtnl_lock();
- list_for_each_entry(neigh_entry, &mlxsw_sp->router.nexthop_neighs_list,
+ list_for_each_entry(neigh_entry, &router->nexthop_neighs_list,
nexthop_neighs_list_node)
if (!neigh_entry->connected)
neigh_event_send(neigh_entry->key.n, NULL);
rtnl_unlock();
- mlxsw_core_schedule_dw(&mlxsw_sp->router.nexthop_probe_dw,
+ mlxsw_core_schedule_dw(&router->nexthop_probe_dw,
MLXSW_SP_UNRESOLVED_NH_PROBE_INTERVAL);
}
@@ -1127,7 +1178,7 @@ int mlxsw_sp_router_netevent_event(struct notifier_block *unused,
mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
interval = jiffies_to_msecs(NEIGH_VAR(p, DELAY_PROBE_TIME));
- mlxsw_sp->router.neighs_update.interval = interval;
+ mlxsw_sp->router->neighs_update.interval = interval;
mlxsw_sp_port_dev_put(mlxsw_sp_port);
break;
@@ -1168,7 +1219,7 @@ static int mlxsw_sp_neigh_init(struct mlxsw_sp *mlxsw_sp)
{
int err;
- err = rhashtable_init(&mlxsw_sp->router.neigh_ht,
+ err = rhashtable_init(&mlxsw_sp->router->neigh_ht,
&mlxsw_sp_neigh_ht_params);
if (err)
return err;
@@ -1179,20 +1230,20 @@ static int mlxsw_sp_neigh_init(struct mlxsw_sp *mlxsw_sp)
mlxsw_sp_router_neighs_update_interval_init(mlxsw_sp);
/* Create the delayed works for the activity_update */
- INIT_DELAYED_WORK(&mlxsw_sp->router.neighs_update.dw,
+ INIT_DELAYED_WORK(&mlxsw_sp->router->neighs_update.dw,
mlxsw_sp_router_neighs_update_work);
- INIT_DELAYED_WORK(&mlxsw_sp->router.nexthop_probe_dw,
+ INIT_DELAYED_WORK(&mlxsw_sp->router->nexthop_probe_dw,
mlxsw_sp_router_probe_unresolved_nexthops);
- mlxsw_core_schedule_dw(&mlxsw_sp->router.neighs_update.dw, 0);
- mlxsw_core_schedule_dw(&mlxsw_sp->router.nexthop_probe_dw, 0);
+ mlxsw_core_schedule_dw(&mlxsw_sp->router->neighs_update.dw, 0);
+ mlxsw_core_schedule_dw(&mlxsw_sp->router->nexthop_probe_dw, 0);
return 0;
}
static void mlxsw_sp_neigh_fini(struct mlxsw_sp *mlxsw_sp)
{
- cancel_delayed_work_sync(&mlxsw_sp->router.neighs_update.dw);
- cancel_delayed_work_sync(&mlxsw_sp->router.nexthop_probe_dw);
- rhashtable_destroy(&mlxsw_sp->router.neigh_ht);
+ cancel_delayed_work_sync(&mlxsw_sp->router->neighs_update.dw);
+ cancel_delayed_work_sync(&mlxsw_sp->router->nexthop_probe_dw);
+ rhashtable_destroy(&mlxsw_sp->router->neigh_ht);
}
static int mlxsw_sp_neigh_rif_flush(struct mlxsw_sp *mlxsw_sp,
@@ -1267,7 +1318,7 @@ static const struct rhashtable_params mlxsw_sp_nexthop_group_ht_params = {
static int mlxsw_sp_nexthop_group_insert(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_nexthop_group *nh_grp)
{
- return rhashtable_insert_fast(&mlxsw_sp->router.nexthop_group_ht,
+ return rhashtable_insert_fast(&mlxsw_sp->router->nexthop_group_ht,
&nh_grp->ht_node,
mlxsw_sp_nexthop_group_ht_params);
}
@@ -1275,7 +1326,7 @@ static int mlxsw_sp_nexthop_group_insert(struct mlxsw_sp *mlxsw_sp,
static void mlxsw_sp_nexthop_group_remove(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_nexthop_group *nh_grp)
{
- rhashtable_remove_fast(&mlxsw_sp->router.nexthop_group_ht,
+ rhashtable_remove_fast(&mlxsw_sp->router->nexthop_group_ht,
&nh_grp->ht_node,
mlxsw_sp_nexthop_group_ht_params);
}
@@ -1284,7 +1335,7 @@ static struct mlxsw_sp_nexthop_group *
mlxsw_sp_nexthop_group_lookup(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_nexthop_group_key key)
{
- return rhashtable_lookup_fast(&mlxsw_sp->router.nexthop_group_ht, &key,
+ return rhashtable_lookup_fast(&mlxsw_sp->router->nexthop_group_ht, &key,
mlxsw_sp_nexthop_group_ht_params);
}
@@ -1297,14 +1348,14 @@ static const struct rhashtable_params mlxsw_sp_nexthop_ht_params = {
static int mlxsw_sp_nexthop_insert(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_nexthop *nh)
{
- return rhashtable_insert_fast(&mlxsw_sp->router.nexthop_ht,
+ return rhashtable_insert_fast(&mlxsw_sp->router->nexthop_ht,
&nh->ht_node, mlxsw_sp_nexthop_ht_params);
}
static void mlxsw_sp_nexthop_remove(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_nexthop *nh)
{
- rhashtable_remove_fast(&mlxsw_sp->router.nexthop_ht, &nh->ht_node,
+ rhashtable_remove_fast(&mlxsw_sp->router->nexthop_ht, &nh->ht_node,
mlxsw_sp_nexthop_ht_params);
}
@@ -1312,7 +1363,7 @@ static struct mlxsw_sp_nexthop *
mlxsw_sp_nexthop_lookup(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_nexthop_key key)
{
- return rhashtable_lookup_fast(&mlxsw_sp->router.nexthop_ht, &key,
+ return rhashtable_lookup_fast(&mlxsw_sp->router->nexthop_ht, &key,
mlxsw_sp_nexthop_ht_params);
}
@@ -1599,7 +1650,7 @@ static int mlxsw_sp_nexthop_neigh_init(struct mlxsw_sp *mlxsw_sp,
*/
if (list_empty(&neigh_entry->nexthop_list))
list_add_tail(&neigh_entry->nexthop_neighs_list_node,
- &mlxsw_sp->router.nexthop_neighs_list);
+ &mlxsw_sp->router->nexthop_neighs_list);
nh->neigh_entry = neigh_entry;
list_add_tail(&nh->neigh_list_node, &neigh_entry->nexthop_list);
@@ -1697,7 +1748,7 @@ static void mlxsw_sp_nexthop_event(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_nexthop *nh;
struct mlxsw_sp_rif *rif;
- if (mlxsw_sp->router.aborted)
+ if (mlxsw_sp->router->aborted)
return;
key.fib_nh = fib_nh;
@@ -2510,7 +2561,7 @@ mlxsw_sp_router_fib4_add(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_node *fib_node;
int err;
- if (mlxsw_sp->router.aborted)
+ if (mlxsw_sp->router->aborted)
return 0;
fib_node = mlxsw_sp_fib4_node_get(mlxsw_sp, fen_info);
@@ -2550,7 +2601,7 @@ static void mlxsw_sp_router_fib4_del(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_fib_entry *fib_entry;
struct mlxsw_sp_fib_node *fib_node;
- if (mlxsw_sp->router.aborted)
+ if (mlxsw_sp->router->aborted)
return;
fib_entry = mlxsw_sp_fib4_entry_lookup(mlxsw_sp, fen_info);
@@ -2581,7 +2632,7 @@ static int mlxsw_sp_router_set_abort_trap(struct mlxsw_sp *mlxsw_sp)
return err;
for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) {
- struct mlxsw_sp_vr *vr = &mlxsw_sp->router.vrs[i];
+ struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[i];
char raltb_pl[MLXSW_REG_RALTB_LEN];
char ralue_pl[MLXSW_REG_RALUE_LEN];
@@ -2663,7 +2714,7 @@ static void mlxsw_sp_router_fib_flush(struct mlxsw_sp *mlxsw_sp)
int i;
for (i = 0; i < MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_VRS); i++) {
- struct mlxsw_sp_vr *vr = &mlxsw_sp->router.vrs[i];
+ struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[i];
if (!mlxsw_sp_vr_is_used(vr))
continue;
@@ -2675,11 +2726,11 @@ static void mlxsw_sp_router_fib4_abort(struct mlxsw_sp *mlxsw_sp)
{
int err;
- if (mlxsw_sp->router.aborted)
+ if (mlxsw_sp->router->aborted)
return;
dev_warn(mlxsw_sp->bus_info->dev, "FIB abort triggered. Note that FIB entries are no longer being offloaded to this device.\n");
mlxsw_sp_router_fib_flush(mlxsw_sp);
- mlxsw_sp->router.aborted = true;
+ mlxsw_sp->router->aborted = true;
err = mlxsw_sp_router_set_abort_trap(mlxsw_sp);
if (err)
dev_warn(mlxsw_sp->bus_info->dev, "Failed to set abort trap.\n");
@@ -3015,7 +3066,7 @@ static void mlxsw_sp_vport_rif_sp_destroy(struct mlxsw_sp_port *mlxsw_sp_vport,
struct mlxsw_sp_rif *rif)
{
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_vport->mlxsw_sp;
- struct mlxsw_sp_vr *vr = &mlxsw_sp->router.vrs[rif->vr_id];
+ struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[rif->vr_id];
struct net_device *l3_dev = rif->dev;
struct mlxsw_sp_fid *f = rif->f;
u16 rif_index = rif->rif_index;
@@ -3273,7 +3324,7 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp,
void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_rif *rif)
{
- struct mlxsw_sp_vr *vr = &mlxsw_sp->router.vrs[rif->vr_id];
+ struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[rif->vr_id];
struct net_device *l3_dev = rif->dev;
struct mlxsw_sp_fid *f = rif->f;
u16 rif_index = rif->rif_index;
@@ -3545,19 +3596,26 @@ static void __mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
{
+ struct mlxsw_sp_router *router;
int err;
- INIT_LIST_HEAD(&mlxsw_sp->router.nexthop_neighs_list);
+ router = kzalloc(sizeof(*mlxsw_sp->router), GFP_KERNEL);
+ if (!router)
+ return -ENOMEM;
+ mlxsw_sp->router = router;
+ router->mlxsw_sp = mlxsw_sp;
+
+ INIT_LIST_HEAD(&mlxsw_sp->router->nexthop_neighs_list);
err = __mlxsw_sp_router_init(mlxsw_sp);
if (err)
- return err;
+ goto err_router_init;
- err = rhashtable_init(&mlxsw_sp->router.nexthop_ht,
+ err = rhashtable_init(&mlxsw_sp->router->nexthop_ht,
&mlxsw_sp_nexthop_ht_params);
if (err)
goto err_nexthop_ht_init;
- err = rhashtable_init(&mlxsw_sp->router.nexthop_group_ht,
+ err = rhashtable_init(&mlxsw_sp->router->nexthop_group_ht,
&mlxsw_sp_nexthop_group_ht_params);
if (err)
goto err_nexthop_group_ht_init;
@@ -3589,11 +3647,13 @@ int mlxsw_sp_router_init(struct mlxsw_sp *mlxsw_sp)
err_vrs_init:
mlxsw_sp_lpm_fini(mlxsw_sp);
err_lpm_init:
- rhashtable_destroy(&mlxsw_sp->router.nexthop_group_ht);
+ rhashtable_destroy(&mlxsw_sp->router->nexthop_group_ht);
err_nexthop_group_ht_init:
- rhashtable_destroy(&mlxsw_sp->router.nexthop_ht);
+ rhashtable_destroy(&mlxsw_sp->router->nexthop_ht);
err_nexthop_ht_init:
__mlxsw_sp_router_fini(mlxsw_sp);
+err_router_init:
+ kfree(mlxsw_sp->router);
return err;
}
@@ -3603,7 +3663,8 @@ void mlxsw_sp_router_fini(struct mlxsw_sp *mlxsw_sp)
mlxsw_sp_neigh_fini(mlxsw_sp);
mlxsw_sp_vrs_fini(mlxsw_sp);
mlxsw_sp_lpm_fini(mlxsw_sp);
- rhashtable_destroy(&mlxsw_sp->router.nexthop_group_ht);
- rhashtable_destroy(&mlxsw_sp->router.nexthop_ht);
+ rhashtable_destroy(&mlxsw_sp->router->nexthop_group_ht);
+ rhashtable_destroy(&mlxsw_sp->router->nexthop_ht);
__mlxsw_sp_router_fini(mlxsw_sp);
+ kfree(mlxsw_sp->router);
}
--
2.9.3
^ permalink raw reply related
* [patch net-next 03/12] mlxsw: spectrum_switchdev: Reduce scope of bridge struct
From: Jiri Pirko @ 2017-05-16 17:38 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, mlxsw
In-Reply-To: <20170516173835.2978-1-jiri@resnulli.us>
From: Ido Schimmel <idosch@mellanox.com>
Some attributes in the global chip struct are only relevant for bridge
operation, so encapsulate them in their own struct that isn't exposed to
non-bridge code.
This will also help us later, when we add more bridge-specific
attributes.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 20 ++++---
drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 17 +-----
.../net/ethernet/mellanox/mlxsw/spectrum_router.c | 4 +-
.../ethernet/mellanox/mlxsw/spectrum_switchdev.c | 65 +++++++++++++++++-----
4 files changed, 69 insertions(+), 37 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index 88357ce..166be18 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -3312,7 +3312,6 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
mlxsw_sp->bus_info = mlxsw_bus_info;
INIT_LIST_HEAD(&mlxsw_sp->fids);
INIT_LIST_HEAD(&mlxsw_sp->vfids.list);
- INIT_LIST_HEAD(&mlxsw_sp->br_mids.list);
err = mlxsw_sp_base_mac_get(mlxsw_sp);
if (err) {
@@ -3659,21 +3658,26 @@ static void mlxsw_sp_master_bridge_gone_sync(struct mlxsw_sp *mlxsw_sp)
static bool mlxsw_sp_master_bridge_check(struct mlxsw_sp *mlxsw_sp,
struct net_device *br_dev)
{
- return !mlxsw_sp->master_bridge.dev ||
- mlxsw_sp->master_bridge.dev == br_dev;
+ struct mlxsw_sp_upper *master_bridge = mlxsw_sp_master_bridge(mlxsw_sp);
+
+ return !master_bridge->dev || master_bridge->dev == br_dev;
}
static void mlxsw_sp_master_bridge_inc(struct mlxsw_sp *mlxsw_sp,
struct net_device *br_dev)
{
- mlxsw_sp->master_bridge.dev = br_dev;
- mlxsw_sp->master_bridge.ref_count++;
+ struct mlxsw_sp_upper *master_bridge = mlxsw_sp_master_bridge(mlxsw_sp);
+
+ master_bridge->dev = br_dev;
+ master_bridge->ref_count++;
}
static void mlxsw_sp_master_bridge_dec(struct mlxsw_sp *mlxsw_sp)
{
- if (--mlxsw_sp->master_bridge.ref_count == 0) {
- mlxsw_sp->master_bridge.dev = NULL;
+ struct mlxsw_sp_upper *master_bridge = mlxsw_sp_master_bridge(mlxsw_sp);
+
+ if (--master_bridge->ref_count == 0) {
+ master_bridge->dev = NULL;
/* It's possible upper VLAN devices are still holding
* references to underlying FIDs. Drop the reference
* and release the resources if it was the last one.
@@ -4272,7 +4276,7 @@ static int mlxsw_sp_netdevice_bridge_event(struct net_device *br_dev,
if (!is_vlan_dev(upper_dev))
return -EINVAL;
if (is_vlan_dev(upper_dev) &&
- br_dev != mlxsw_sp->master_bridge.dev)
+ br_dev != mlxsw_sp_master_bridge(mlxsw_sp)->dev)
return -EINVAL;
break;
case NETDEV_CHANGEUPPER:
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
index 2eb2230..7c9e2f1 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@ -149,6 +149,7 @@ struct mlxsw_sp_port_mall_tc_entry {
};
struct mlxsw_sp_sb;
+struct mlxsw_sp_bridge;
struct mlxsw_sp_router;
struct mlxsw_sp_acl;
struct mlxsw_sp_counter_pool;
@@ -158,29 +159,16 @@ struct mlxsw_sp {
struct list_head list;
DECLARE_BITMAP(mapped, MLXSW_SP_VFID_MAX);
} vfids;
- struct {
- struct list_head list;
- DECLARE_BITMAP(mapped, MLXSW_SP_MID_MAX);
- } br_mids;
struct list_head fids; /* VLAN-aware bridge FIDs */
struct mlxsw_sp_rif **rifs;
struct mlxsw_sp_port **ports;
struct mlxsw_core *core;
const struct mlxsw_bus_info *bus_info;
unsigned char base_mac[ETH_ALEN];
- struct {
- struct delayed_work dw;
-#define MLXSW_SP_DEFAULT_LEARNING_INTERVAL 100
- unsigned int interval; /* ms */
- } fdb_notify;
-#define MLXSW_SP_MIN_AGEING_TIME 10
-#define MLXSW_SP_MAX_AGEING_TIME 1000000
-#define MLXSW_SP_DEFAULT_AGEING_TIME 300
- u32 ageing_time;
- struct mlxsw_sp_upper master_bridge;
struct mlxsw_sp_upper *lags;
u8 *port_to_module;
struct mlxsw_sp_sb *sb;
+ struct mlxsw_sp_bridge *bridge;
struct mlxsw_sp_router *router;
struct mlxsw_sp_acl *acl;
struct {
@@ -425,6 +413,7 @@ int mlxsw_sp_sb_occ_tc_port_bind_get(struct mlxsw_core_port *mlxsw_core_port,
u32 mlxsw_sp_cells_bytes(const struct mlxsw_sp *mlxsw_sp, u32 cells);
u32 mlxsw_sp_bytes_cells(const struct mlxsw_sp *mlxsw_sp, u32 bytes);
+struct mlxsw_sp_upper *mlxsw_sp_master_bridge(const struct mlxsw_sp *mlxsw_sp);
int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp);
void mlxsw_sp_switchdev_fini(struct mlxsw_sp *mlxsw_sp);
int mlxsw_sp_port_vlan_init(struct mlxsw_sp_port *mlxsw_sp_port);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index 28f7f54..434e091 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -3193,7 +3193,7 @@ static struct mlxsw_sp_fid *mlxsw_sp_bridge_fid_get(struct mlxsw_sp *mlxsw_sp,
if (is_vlan_dev(l3_dev))
fid = vlan_dev_vlan_id(l3_dev);
- else if (mlxsw_sp->master_bridge.dev == l3_dev)
+ else if (mlxsw_sp_master_bridge(mlxsw_sp)->dev == l3_dev)
fid = 1;
else
return mlxsw_sp_vfid_find(mlxsw_sp, l3_dev);
@@ -3389,7 +3389,7 @@ static int mlxsw_sp_inetaddr_vlan_event(struct net_device *vlan_dev,
return __mlxsw_sp_inetaddr_lag_event(vlan_dev, real_dev, event,
vid);
else if (netif_is_bridge_master(real_dev) &&
- mlxsw_sp->master_bridge.dev == real_dev)
+ mlxsw_sp_master_bridge(mlxsw_sp)->dev == real_dev)
return mlxsw_sp_inetaddr_bridge_event(vlan_dev, real_dev,
event);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
index 0d8411f..85790d3 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
@@ -52,6 +52,27 @@
#include "core.h"
#include "reg.h"
+struct mlxsw_sp_bridge {
+ struct mlxsw_sp *mlxsw_sp;
+ struct {
+ struct delayed_work dw;
+#define MLXSW_SP_DEFAULT_LEARNING_INTERVAL 100
+ unsigned int interval; /* ms */
+ } fdb_notify;
+#define MLXSW_SP_MIN_AGEING_TIME 10
+#define MLXSW_SP_MAX_AGEING_TIME 1000000
+#define MLXSW_SP_DEFAULT_AGEING_TIME 300
+ u32 ageing_time;
+ struct mlxsw_sp_upper master_bridge;
+ struct list_head mids_list;
+ DECLARE_BITMAP(mids_bitmap, MLXSW_SP_MID_MAX);
+};
+
+struct mlxsw_sp_upper *mlxsw_sp_master_bridge(const struct mlxsw_sp *mlxsw_sp)
+{
+ return &mlxsw_sp->bridge->master_bridge;
+}
+
static u16 mlxsw_sp_port_vid_to_fid_get(struct mlxsw_sp_port *mlxsw_sp_port,
u16 vid)
{
@@ -397,7 +418,7 @@ static int mlxsw_sp_ageing_set(struct mlxsw_sp *mlxsw_sp, u32 ageing_time)
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfdat), sfdat_pl);
if (err)
return err;
- mlxsw_sp->ageing_time = ageing_time;
+ mlxsw_sp->bridge->ageing_time = ageing_time;
return 0;
}
@@ -428,7 +449,8 @@ static int mlxsw_sp_port_attr_br_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port,
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
/* SWITCHDEV_TRANS_PREPARE phase */
- if ((!vlan_enabled) && (mlxsw_sp->master_bridge.dev == orig_dev)) {
+ if ((!vlan_enabled) &&
+ (mlxsw_sp->bridge->master_bridge.dev == orig_dev)) {
netdev_err(mlxsw_sp_port->dev, "Bridge must be vlan-aware\n");
return -EINVAL;
}
@@ -1006,7 +1028,7 @@ static struct mlxsw_sp_mid *__mlxsw_sp_mc_get(struct mlxsw_sp *mlxsw_sp,
{
struct mlxsw_sp_mid *mid;
- list_for_each_entry(mid, &mlxsw_sp->br_mids.list, list) {
+ list_for_each_entry(mid, &mlxsw_sp->bridge->mids_list, list) {
if (ether_addr_equal(mid->addr, addr) && mid->fid == fid)
return mid;
}
@@ -1020,7 +1042,7 @@ static struct mlxsw_sp_mid *__mlxsw_sp_mc_alloc(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_mid *mid;
u16 mid_idx;
- mid_idx = find_first_zero_bit(mlxsw_sp->br_mids.mapped,
+ mid_idx = find_first_zero_bit(mlxsw_sp->bridge->mids_bitmap,
MLXSW_SP_MID_MAX);
if (mid_idx == MLXSW_SP_MID_MAX)
return NULL;
@@ -1029,12 +1051,12 @@ static struct mlxsw_sp_mid *__mlxsw_sp_mc_alloc(struct mlxsw_sp *mlxsw_sp,
if (!mid)
return NULL;
- set_bit(mid_idx, mlxsw_sp->br_mids.mapped);
+ set_bit(mid_idx, mlxsw_sp->bridge->mids_bitmap);
ether_addr_copy(mid->addr, addr);
mid->fid = fid;
mid->mid = mid_idx;
mid->ref_count = 0;
- list_add_tail(&mid->list, &mlxsw_sp->br_mids.list);
+ list_add_tail(&mid->list, &mlxsw_sp->bridge->mids_list);
return mid;
}
@@ -1044,7 +1066,7 @@ static int __mlxsw_sp_mc_dec_ref(struct mlxsw_sp *mlxsw_sp,
{
if (--mid->ref_count == 0) {
list_del(&mid->list);
- clear_bit(mid->mid, mlxsw_sp->br_mids.mapped);
+ clear_bit(mid->mid, mlxsw_sp->bridge->mids_bitmap);
kfree(mid);
return 1;
}
@@ -1600,12 +1622,15 @@ static void mlxsw_sp_fdb_notify_rec_process(struct mlxsw_sp *mlxsw_sp,
static void mlxsw_sp_fdb_notify_work_schedule(struct mlxsw_sp *mlxsw_sp)
{
- mlxsw_core_schedule_dw(&mlxsw_sp->fdb_notify.dw,
- msecs_to_jiffies(mlxsw_sp->fdb_notify.interval));
+ struct mlxsw_sp_bridge *bridge = mlxsw_sp->bridge;
+
+ mlxsw_core_schedule_dw(&bridge->fdb_notify.dw,
+ msecs_to_jiffies(bridge->fdb_notify.interval));
}
static void mlxsw_sp_fdb_notify_work(struct work_struct *work)
{
+ struct mlxsw_sp_bridge *bridge;
struct mlxsw_sp *mlxsw_sp;
char *sfn_pl;
u8 num_rec;
@@ -1616,7 +1641,8 @@ static void mlxsw_sp_fdb_notify_work(struct work_struct *work)
if (!sfn_pl)
return;
- mlxsw_sp = container_of(work, struct mlxsw_sp, fdb_notify.dw.work);
+ bridge = container_of(work, struct mlxsw_sp_bridge, fdb_notify.dw.work);
+ mlxsw_sp = bridge->mlxsw_sp;
rtnl_lock();
mlxsw_reg_sfn_pack(sfn_pl);
@@ -1637,6 +1663,7 @@ static void mlxsw_sp_fdb_notify_work(struct work_struct *work)
static int mlxsw_sp_fdb_init(struct mlxsw_sp *mlxsw_sp)
{
+ struct mlxsw_sp_bridge *bridge = mlxsw_sp->bridge;
int err;
err = mlxsw_sp_ageing_set(mlxsw_sp, MLXSW_SP_DEFAULT_AGEING_TIME);
@@ -1644,25 +1671,37 @@ static int mlxsw_sp_fdb_init(struct mlxsw_sp *mlxsw_sp)
dev_err(mlxsw_sp->bus_info->dev, "Failed to set default ageing time\n");
return err;
}
- INIT_DELAYED_WORK(&mlxsw_sp->fdb_notify.dw, mlxsw_sp_fdb_notify_work);
- mlxsw_sp->fdb_notify.interval = MLXSW_SP_DEFAULT_LEARNING_INTERVAL;
+ INIT_DELAYED_WORK(&bridge->fdb_notify.dw, mlxsw_sp_fdb_notify_work);
+ bridge->fdb_notify.interval = MLXSW_SP_DEFAULT_LEARNING_INTERVAL;
mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp);
return 0;
}
static void mlxsw_sp_fdb_fini(struct mlxsw_sp *mlxsw_sp)
{
- cancel_delayed_work_sync(&mlxsw_sp->fdb_notify.dw);
+ cancel_delayed_work_sync(&mlxsw_sp->bridge->fdb_notify.dw);
}
int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp)
{
+ struct mlxsw_sp_bridge *bridge;
+
+ bridge = kzalloc(sizeof(*mlxsw_sp->bridge), GFP_KERNEL);
+ if (!bridge)
+ return -ENOMEM;
+ mlxsw_sp->bridge = bridge;
+ bridge->mlxsw_sp = mlxsw_sp;
+
+ INIT_LIST_HEAD(&mlxsw_sp->bridge->mids_list);
+
return mlxsw_sp_fdb_init(mlxsw_sp);
}
void mlxsw_sp_switchdev_fini(struct mlxsw_sp *mlxsw_sp)
{
mlxsw_sp_fdb_fini(mlxsw_sp);
+ WARN_ON(!list_empty(&mlxsw_sp->bridge->mids_list));
+ kfree(mlxsw_sp->bridge);
}
void mlxsw_sp_port_switchdev_init(struct mlxsw_sp_port *mlxsw_sp_port)
--
2.9.3
^ permalink raw reply related
* [patch net-next 07/12] mlxsw: spectrum_switchdev: Remove redundant check
From: Jiri Pirko @ 2017-05-16 17:38 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, mlxsw
In-Reply-To: <20170516173835.2978-1-jiri@resnulli.us>
From: Ido Schimmel <idosch@mellanox.com>
Since commit 97c242902c20 ("switchdev: Execute bridge ndos only for
bridge ports") switchdev code checks that port is bridged, so no need to
perform the same check in the driver.
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 9 ---------
1 file changed, 9 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
index 85790d3..d9393f7 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
@@ -374,9 +374,6 @@ static int mlxsw_sp_port_attr_br_flags_set(struct mlxsw_sp_port *mlxsw_sp_port,
unsigned long uc_flood = mlxsw_sp_port->uc_flood ? BR_FLOOD : 0;
int err;
- if (!mlxsw_sp_port->bridged)
- return -EINVAL;
-
if (switchdev_trans_ph_prepare(trans))
return 0;
@@ -796,9 +793,6 @@ static int __mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port,
u16 vid, old_pvid;
int err;
- if (!mlxsw_sp_port->bridged)
- return -EINVAL;
-
err = mlxsw_sp_port_fid_join(mlxsw_sp_port, vid_begin, vid_end);
if (err) {
netdev_err(dev, "Failed to join FIDs\n");
@@ -1162,9 +1156,6 @@ static int __mlxsw_sp_port_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port,
{
u16 vid, pvid;
- if (!mlxsw_sp_port->bridged)
- return -EINVAL;
-
mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid_begin, vid_end,
false);
--
2.9.3
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox