summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2016-08-18 21:19:09 -0700
committerDavid S. Miller <davem@davemloft.net>2016-08-18 21:19:09 -0700
commit3e7d2d45644988ceb237349a923e9ccc909564d3 (patch)
tree3c2021737a3e03e57190ccfc5c9c33a0fc4f2e07
parente951f145d1724769546efe2e04f6cb2b7037d7ea (diff)
parentea3274695353127d12155d45be1f2d62ab19c897 (diff)
Merge branch 'qdisc-hash-fixes'
Jiri Kosina says: ==================== qdisc-hashtable fixes The following two patches fix all the issues that have been reported against the conversion of qdisc linked list to hashtable (currently in net-next) so far. First patch adjusts handling of singleton qdiscs to the new semantics, and is rather straightforward. The second patch, which fixes "cosmetic" issue of duplicate entries in the qdisc dump for ingress qdiscs, is a little bit more hairy; I personally would love to see all the already existing "if (ingress)"-like hacks go away (by, let's say, introducing a general TCQ_F_? flag), but that's way out of scope of this patchset (but already on my todo). Thanks a lot to Daniel Borkmann and David Ahern for reporting the issues and testing the patches promptly. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/sched/sch_api.c22
1 files changed, 19 insertions, 3 deletions
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index 25aada7b095c..d677b3484d81 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -260,6 +260,9 @@ static struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle)
{
struct Qdisc *q;
+ if (!qdisc_dev(root))
+ return (root->handle == handle ? root : NULL);
+
if (!(root->flags & TCQ_F_BUILTIN) &&
root->handle == handle)
return root;
@@ -1432,7 +1435,7 @@ err_out:
static int tc_dump_qdisc_root(struct Qdisc *root, struct sk_buff *skb,
struct netlink_callback *cb,
- int *q_idx_p, int s_q_idx)
+ int *q_idx_p, int s_q_idx, bool recur)
{
int ret = 0, q_idx = *q_idx_p;
struct Qdisc *q;
@@ -1451,6 +1454,16 @@ static int tc_dump_qdisc_root(struct Qdisc *root, struct sk_buff *skb,
goto done;
q_idx++;
}
+
+ /* If dumping singletons, there is no qdisc_dev(root) and the singleton
+ * itself has already been dumped.
+ *
+ * If we've already dumped the top-level (ingress) qdisc above and the global
+ * qdisc hashtable, we don't want to hit it again
+ */
+ if (!qdisc_dev(root) || !recur)
+ goto out;
+
hash_for_each(qdisc_dev(root)->qdisc_hash, b, q, hash) {
if (q_idx < s_q_idx) {
q_idx++;
@@ -1492,13 +1505,13 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
s_q_idx = 0;
q_idx = 0;
- if (tc_dump_qdisc_root(dev->qdisc, skb, cb, &q_idx, s_q_idx) < 0)
+ if (tc_dump_qdisc_root(dev->qdisc, skb, cb, &q_idx, s_q_idx, true) < 0)
goto done;
dev_queue = dev_ingress_queue(dev);
if (dev_queue &&
tc_dump_qdisc_root(dev_queue->qdisc_sleeping, skb, cb,
- &q_idx, s_q_idx) < 0)
+ &q_idx, s_q_idx, false) < 0)
goto done;
cont:
@@ -1775,6 +1788,9 @@ static int tc_dump_tclass_root(struct Qdisc *root, struct sk_buff *skb,
if (tc_dump_tclass_qdisc(root, skb, tcm, cb, t_p, s_t) < 0)
return -1;
+ if (!qdisc_dev(root))
+ return 0;
+
hash_for_each(qdisc_dev(root)->qdisc_hash, b, q, hash) {
if (tc_dump_tclass_qdisc(q, skb, tcm, cb, t_p, s_t) < 0)
return -1;