|
@@ -1435,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;
|
|
@@ -1455,7 +1455,13 @@ static int tc_dump_qdisc_root(struct Qdisc *root, struct sk_buff *skb,
|
|
|
q_idx++;
|
|
|
}
|
|
|
|
|
|
- if (!qdisc_dev(root))
|
|
|
+ /* 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) {
|
|
@@ -1499,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:
|