From: Jiri Pirko <jiri@resnulli.us>
To: netdev@vger.kernel.org
Cc: davem@davemloft.net, jhs@mojatatu.com, xiyou.wangcong@gmail.com,
dsa@cumulusnetworks.com, edumazet@google.com,
stephen@networkplumber.org, daniel@iogearbox.net,
alexander.h.duyck@intel.com, simon.horman@netronome.com,
mlxsw@mellanox.com
Subject: [patch net-next v3 08/10] net: sched: introduce multichain support for filters
Date: Tue, 16 May 2017 19:28:00 +0200 [thread overview]
Message-ID: <20170516172802.1317-9-jiri@resnulli.us> (raw)
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
next prev parent reply other threads:[~2017-05-16 17:28 UTC|newest]
Thread overview: 45+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-05-16 17:27 [patch net-next v3 00/10] net: sched: introduce multichain support for filters Jiri Pirko
2017-05-16 17:27 ` [patch net-next v3 01/10] net: sched: move tc_classify function to cls_api.c Jiri Pirko
2017-05-16 20:25 ` Cong Wang
2017-05-16 21:00 ` Jiri Pirko
2017-05-16 21:03 ` Cong Wang
2017-05-16 21:05 ` Jiri Pirko
2017-05-16 17:27 ` [patch net-next v3 02/10] net: sched: introduce tcf block infractructure Jiri Pirko
2017-05-16 20:51 ` Cong Wang
2017-05-16 20:57 ` Jiri Pirko
2017-05-16 21:34 ` David Miller
2017-05-16 22:34 ` Cong Wang
2017-05-17 5:42 ` Jiri Pirko
2017-05-16 17:27 ` [patch net-next v3 03/10] net: sched: rename tcf_destroy_chain helper Jiri Pirko
2017-05-16 17:27 ` [patch net-next v3 04/10] net: sched: replace nprio by a bool to make the function more readable Jiri Pirko
2017-05-16 17:27 ` [patch net-next v3 05/10] net: sched: move TC_H_MAJ macro call into tcf_auto_prio Jiri Pirko
2017-05-16 21:01 ` Cong Wang
2017-05-16 21:03 ` Jiri Pirko
2017-05-16 22:38 ` Cong Wang
2017-05-17 5:47 ` Jiri Pirko
2017-05-17 12:47 ` Jamal Hadi Salim
2017-05-17 12:53 ` Jiri Pirko
2017-05-16 17:27 ` [patch net-next v3 06/10] net: sched: introduce helpers to work with filter chains Jiri Pirko
2017-05-16 22:17 ` Cong Wang
2017-05-17 5:50 ` Jiri Pirko
2017-05-16 17:27 ` [patch net-next v3 07/10] net: sched: push chain dump to a separate function Jiri Pirko
2017-05-16 17:28 ` Jiri Pirko [this message]
2017-05-16 17:28 ` [patch net-next v3 09/10] net: sched: push tp down to action init Jiri Pirko
2017-05-16 17:28 ` [patch net-next v3 10/10] net: sched: add termination action to allow goto chain Jiri Pirko
2017-05-16 17:29 ` [patch iproute2 v2 repost 1/3] tc_filter: add support for chain index Jiri Pirko
2017-05-16 18:16 ` Stephen Hemminger
2017-05-16 19:47 ` Jiri Pirko
2017-05-22 20:33 ` Stephen Hemminger
2017-05-23 13:40 ` Jiri Pirko
2017-05-26 19:48 ` Daniel Borkmann
2017-05-27 0:11 ` Stephen Hemminger
2017-05-27 0:24 ` Daniel Borkmann
2017-05-16 17:29 ` [patch iproute2 v2 repost 2/3] tc: actions: add helpers to parse and print control actions Jiri Pirko
2017-06-14 18:32 ` Jiri Benc
2017-06-14 19:18 ` Jiri Pirko
2017-06-14 19:28 ` Jiri Benc
2017-06-14 20:10 ` Jiri Pirko
2017-05-16 17:29 ` [patch iproute2 v2 repost 3/3] tc/actions: introduce support for goto chain action Jiri Pirko
2017-05-31 12:27 ` Jiri Benc
2017-06-02 8:15 ` Jiri Pirko
2017-06-02 8:22 ` Jiri Benc
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20170516172802.1317-9-jiri@resnulli.us \
--to=jiri@resnulli.us \
--cc=alexander.h.duyck@intel.com \
--cc=daniel@iogearbox.net \
--cc=davem@davemloft.net \
--cc=dsa@cumulusnetworks.com \
--cc=edumazet@google.com \
--cc=jhs@mojatatu.com \
--cc=mlxsw@mellanox.com \
--cc=netdev@vger.kernel.org \
--cc=simon.horman@netronome.com \
--cc=stephen@networkplumber.org \
--cc=xiyou.wangcong@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).