summaryrefslogtreecommitdiffstats
path: root/net/sched
diff options
context:
space:
mode:
authorJiri Pirko <jiri@mellanox.com>2018-07-27 09:45:05 +0200
committerDavid S. Miller <davem@davemloft.net>2018-07-27 09:38:46 -0700
commit1f3ed383fb9a073ae2e408cd7a0717b04c7c3a21 (patch)
tree823f398d9c83214306a5cfb09a12c032fe3b91c6 /net/sched
parent7a49d3d4ea42fe15db0d36e042df14a645d1fdce (diff)
downloadlinux-1f3ed383fb9a073ae2e408cd7a0717b04c7c3a21.tar.bz2
net: sched: don't dump chains only held by actions
In case a chain is empty and not explicitly created by a user, such chain should not exist. The only exception is if there is an action "goto chain" pointing to it. In that case, don't show the chain in the dump. Track the chain references held by actions and use them to find out if a chain should or should not be shown in chain dump. Signed-off-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sched')
-rw-r--r--net/sched/act_api.c4
-rw-r--r--net/sched/cls_api.c70
2 files changed, 60 insertions, 14 deletions
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index 148a89ab789b..b43df1e25c6d 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -36,7 +36,7 @@ static int tcf_action_goto_chain_init(struct tc_action *a, struct tcf_proto *tp)
if (!tp)
return -EINVAL;
- a->goto_chain = tcf_chain_get(tp->chain->block, chain_index, true);
+ a->goto_chain = tcf_chain_get_by_act(tp->chain->block, chain_index);
if (!a->goto_chain)
return -ENOMEM;
return 0;
@@ -44,7 +44,7 @@ static int tcf_action_goto_chain_init(struct tc_action *a, struct tcf_proto *tp)
static void tcf_action_goto_chain_fini(struct tc_action *a)
{
- tcf_chain_put(a->goto_chain);
+ tcf_chain_put_by_act(a->goto_chain);
}
static void tcf_action_goto_chain_exec(const struct tc_action *a,
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 75cce2819de9..e20aad1987b8 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -262,6 +262,25 @@ static void tcf_chain_hold(struct tcf_chain *chain)
++chain->refcnt;
}
+static void tcf_chain_hold_by_act(struct tcf_chain *chain)
+{
+ ++chain->action_refcnt;
+}
+
+static void tcf_chain_release_by_act(struct tcf_chain *chain)
+{
+ --chain->action_refcnt;
+}
+
+static bool tcf_chain_is_zombie(struct tcf_chain *chain)
+{
+ /* In case all the references are action references, this
+ * chain is a zombie and should not be listed in the chain
+ * dump list.
+ */
+ return chain->refcnt == chain->action_refcnt;
+}
+
static struct tcf_chain *tcf_chain_lookup(struct tcf_block *block,
u32 chain_index)
{
@@ -298,6 +317,15 @@ struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index,
}
EXPORT_SYMBOL(tcf_chain_get);
+struct tcf_chain *tcf_chain_get_by_act(struct tcf_block *block, u32 chain_index)
+{
+ struct tcf_chain *chain = tcf_chain_get(block, chain_index, true);
+
+ tcf_chain_hold_by_act(chain);
+ return chain;
+}
+EXPORT_SYMBOL(tcf_chain_get_by_act);
+
static void tc_chain_tmplt_del(struct tcf_chain *chain);
void tcf_chain_put(struct tcf_chain *chain)
@@ -310,6 +338,13 @@ void tcf_chain_put(struct tcf_chain *chain)
}
EXPORT_SYMBOL(tcf_chain_put);
+void tcf_chain_put_by_act(struct tcf_chain *chain)
+{
+ tcf_chain_release_by_act(chain);
+ tcf_chain_put(chain);
+}
+EXPORT_SYMBOL(tcf_chain_put_by_act);
+
static void tcf_chain_put_explicitly_created(struct tcf_chain *chain)
{
if (chain->explicitly_created)
@@ -1803,20 +1838,29 @@ replay:
chain = tcf_chain_lookup(block, chain_index);
if (n->nlmsg_type == RTM_NEWCHAIN) {
if (chain) {
- NL_SET_ERR_MSG(extack, "Filter chain already exists");
- return -EEXIST;
- }
- if (!(n->nlmsg_flags & NLM_F_CREATE)) {
- NL_SET_ERR_MSG(extack, "Need both RTM_NEWCHAIN and NLM_F_CREATE to create a new chain");
- return -ENOENT;
- }
- chain = tcf_chain_create(block, chain_index);
- if (!chain) {
- NL_SET_ERR_MSG(extack, "Failed to create filter chain");
- return -ENOMEM;
+ if (tcf_chain_is_zombie(chain)) {
+ /* The chain exists only because there is
+ * some action referencing it, meaning it
+ * is a zombie.
+ */
+ tcf_chain_hold(chain);
+ } else {
+ NL_SET_ERR_MSG(extack, "Filter chain already exists");
+ return -EEXIST;
+ }
+ } else {
+ if (!(n->nlmsg_flags & NLM_F_CREATE)) {
+ NL_SET_ERR_MSG(extack, "Need both RTM_NEWCHAIN and NLM_F_CREATE to create a new chain");
+ return -ENOENT;
+ }
+ chain = tcf_chain_create(block, chain_index);
+ if (!chain) {
+ NL_SET_ERR_MSG(extack, "Failed to create filter chain");
+ return -ENOMEM;
+ }
}
} else {
- if (!chain) {
+ if (!chain || tcf_chain_is_zombie(chain)) {
NL_SET_ERR_MSG(extack, "Cannot find specified filter chain");
return -EINVAL;
}
@@ -1944,6 +1988,8 @@ static int tc_dump_chain(struct sk_buff *skb, struct netlink_callback *cb)
index++;
continue;
}
+ if (tcf_chain_is_zombie(chain))
+ continue;
err = tc_chain_fill_node(chain, net, skb, block,
NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, NLM_F_MULTI,