Skip to content

Commit

Permalink
net: sched: make default fifo qdiscs appear in the dump
Browse files Browse the repository at this point in the history
The original reason [1] for having hidden qdiscs (potential scalability
issues in qdisc_match_from_root() with single linked list in case of large
amount of qdiscs) has been invalidated by 59cc1f6 ("net: sched: convert
qdisc linked list to hashtable").

This allows us for bringing more clarity and determinism into the dump by
making default pfifo qdiscs visible.

We're not turning this on by default though, at it was deemed [2] too
intrusive / unnecessary change of default behavior towards userspace.
Instead, TCA_DUMP_INVISIBLE netlink attribute is introduced, which allows
applications to request complete qdisc hierarchy dump, including the
ones that have always been implicit/invisible.

Singleton noop_qdisc stays invisible, as teaching the whole infrastructure
about singletons would require quite some surgery with very little gain
(seeing no qdisc or seeing noop qdisc in the dump is probably setting
the same user expectation).

[1] http://lkml.kernel.org/r/[email protected]
[2] http://lkml.kernel.org/r/[email protected]

Signed-off-by: Jiri Kosina <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
Jiri Kosina authored and davem330 committed Mar 13, 2017
1 parent 5e8456f commit 49b4997
Show file tree
Hide file tree
Showing 18 changed files with 65 additions and 17 deletions.
2 changes: 1 addition & 1 deletion include/net/pkt_sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ int unregister_qdisc(struct Qdisc_ops *qops);
void qdisc_get_default(char *id, size_t len);
int qdisc_set_default(const char *id);

void qdisc_hash_add(struct Qdisc *q);
void qdisc_hash_add(struct Qdisc *q, bool invisible);
void qdisc_hash_del(struct Qdisc *q);
struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle);
struct Qdisc *qdisc_lookup_class(struct net_device *dev, u32 handle);
Expand Down
1 change: 1 addition & 0 deletions include/net/sch_generic.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ struct Qdisc {
#define TCQ_F_NOPARENT 0x40 /* root of its hierarchy :
* qdisc_tree_decrease_qlen() should stop.
*/
#define TCQ_F_INVISIBLE 0x80 /* invisible by default in dump */
u32 limit;
const struct Qdisc_ops *ops;
struct qdisc_size_table __rcu *stab;
Expand Down
1 change: 1 addition & 0 deletions include/uapi/linux/rtnetlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,7 @@ enum {
TCA_STATS2,
TCA_STAB,
TCA_PAD,
TCA_DUMP_INVISIBLE,
__TCA_MAX
};

Expand Down
42 changes: 30 additions & 12 deletions net/sched/sch_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -274,14 +274,16 @@ static struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle)
return NULL;
}

void qdisc_hash_add(struct Qdisc *q)
void qdisc_hash_add(struct Qdisc *q, bool invisible)
{
if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) {
struct Qdisc *root = qdisc_dev(q)->qdisc;

WARN_ON_ONCE(root == &noop_qdisc);
ASSERT_RTNL();
hash_add_rcu(qdisc_dev(q)->qdisc_hash, &q->hash, q->handle);
if (invisible)
q->flags |= TCQ_F_INVISIBLE;
}
}
EXPORT_SYMBOL(qdisc_hash_add);
Expand Down Expand Up @@ -1003,7 +1005,7 @@ static struct Qdisc *qdisc_create(struct net_device *dev,
goto err_out4;
}

qdisc_hash_add(sch);
qdisc_hash_add(sch, false);

return sch;
}
Expand Down Expand Up @@ -1401,9 +1403,14 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,
return -1;
}

static bool tc_qdisc_dump_ignore(struct Qdisc *q)
static bool tc_qdisc_dump_ignore(struct Qdisc *q, bool dump_invisible)
{
return (q->flags & TCQ_F_BUILTIN) ? true : false;
if (q->flags & TCQ_F_BUILTIN)
return true;
if ((q->flags & TCQ_F_INVISIBLE) && !dump_invisible)
return true;

return false;
}

static int qdisc_notify(struct net *net, struct sk_buff *oskb,
Expand All @@ -1417,12 +1424,12 @@ static int qdisc_notify(struct net *net, struct sk_buff *oskb,
if (!skb)
return -ENOBUFS;

if (old && !tc_qdisc_dump_ignore(old)) {
if (old && !tc_qdisc_dump_ignore(old, false)) {
if (tc_fill_qdisc(skb, old, clid, portid, n->nlmsg_seq,
0, RTM_DELQDISC) < 0)
goto err_out;
}
if (new && !tc_qdisc_dump_ignore(new)) {
if (new && !tc_qdisc_dump_ignore(new, false)) {
if (tc_fill_qdisc(skb, new, clid, portid, n->nlmsg_seq,
old ? NLM_F_REPLACE : 0, RTM_NEWQDISC) < 0)
goto err_out;
Expand All @@ -1439,7 +1446,8 @@ static int qdisc_notify(struct net *net, struct sk_buff *oskb,

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, bool recur)
int *q_idx_p, int s_q_idx, bool recur,
bool dump_invisible)
{
int ret = 0, q_idx = *q_idx_p;
struct Qdisc *q;
Expand All @@ -1452,7 +1460,7 @@ static int tc_dump_qdisc_root(struct Qdisc *root, struct sk_buff *skb,
if (q_idx < s_q_idx) {
q_idx++;
} else {
if (!tc_qdisc_dump_ignore(q) &&
if (!tc_qdisc_dump_ignore(q, dump_invisible) &&
tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, NLM_F_MULTI,
RTM_NEWQDISC) <= 0)
Expand All @@ -1474,7 +1482,7 @@ static int tc_dump_qdisc_root(struct Qdisc *root, struct sk_buff *skb,
q_idx++;
continue;
}
if (!tc_qdisc_dump_ignore(q) &&
if (!tc_qdisc_dump_ignore(q, dump_invisible) &&
tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, NLM_F_MULTI,
RTM_NEWQDISC) <= 0)
Expand All @@ -1496,12 +1504,21 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
int idx, q_idx;
int s_idx, s_q_idx;
struct net_device *dev;
const struct nlmsghdr *nlh = cb->nlh;
struct tcmsg *tcm = nlmsg_data(nlh);
struct nlattr *tca[TCA_MAX + 1];
int err;

s_idx = cb->args[0];
s_q_idx = q_idx = cb->args[1];

idx = 0;
ASSERT_RTNL();

err = nlmsg_parse(nlh, sizeof(*tcm), tca, TCA_MAX, NULL);
if (err < 0)
return err;

for_each_netdev(net, dev) {
struct netdev_queue *dev_queue;

Expand All @@ -1512,13 +1529,14 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
q_idx = 0;

if (tc_dump_qdisc_root(dev->qdisc, skb, cb, &q_idx, s_q_idx,
true) < 0)
true, tca[TCA_DUMP_INVISIBLE]) < 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, false) < 0)
&q_idx, s_q_idx, false,
tca[TCA_DUMP_INVISIBLE]) < 0)
goto done;

cont:
Expand Down Expand Up @@ -1762,7 +1780,7 @@ static int tc_dump_tclass_qdisc(struct Qdisc *q, struct sk_buff *skb,
{
struct qdisc_dump_args arg;

if (tc_qdisc_dump_ignore(q) ||
if (tc_qdisc_dump_ignore(q, false) ||
*t_p < s_t || !q->ops->cl_ops ||
(tcm->tcm_parent &&
TC_H_MAJ(tcm->tcm_parent) != q->handle)) {
Expand Down
5 changes: 5 additions & 0 deletions net/sched/sch_cbq.c
Original file line number Diff line number Diff line change
Expand Up @@ -1161,6 +1161,8 @@ static int cbq_init(struct Qdisc *sch, struct nlattr *opt)
sch->handle);
if (!q->link.q)
q->link.q = &noop_qdisc;
else
qdisc_hash_add(q->link.q, true);

q->link.priority = TC_CBQ_MAXPRIO - 1;
q->link.priority2 = TC_CBQ_MAXPRIO - 1;
Expand Down Expand Up @@ -1600,6 +1602,9 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
cl->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, classid);
if (!cl->q)
cl->q = &noop_qdisc;
else
qdisc_hash_add(cl->q, true);

cl->common.classid = classid;
cl->tparent = parent;
cl->qdisc = sch;
Expand Down
2 changes: 2 additions & 0 deletions net/sched/sch_drr.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
&pfifo_qdisc_ops, classid);
if (cl->qdisc == NULL)
cl->qdisc = &noop_qdisc;
else
qdisc_hash_add(cl->qdisc, true);

if (tca[TCA_RATE]) {
err = gen_replace_estimator(&cl->bstats, NULL, &cl->rate_est,
Expand Down
2 changes: 2 additions & 0 deletions net/sched/sch_dsmark.c
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,8 @@ static int dsmark_init(struct Qdisc *sch, struct nlattr *opt)
p->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, sch->handle);
if (p->q == NULL)
p->q = &noop_qdisc;
else
qdisc_hash_add(p->q, true);

pr_debug("%s: qdisc %p\n", __func__, p->q);

Expand Down
2 changes: 1 addition & 1 deletion net/sched/sch_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -795,7 +795,7 @@ static void attach_default_qdiscs(struct net_device *dev)
}
#ifdef CONFIG_NET_SCHED
if (dev->qdisc)
qdisc_hash_add(dev->qdisc);
qdisc_hash_add(dev->qdisc, false);
#endif
}

Expand Down
4 changes: 4 additions & 0 deletions net/sched/sch_hfsc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1066,6 +1066,8 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
&pfifo_qdisc_ops, classid);
if (cl->qdisc == NULL)
cl->qdisc = &noop_qdisc;
else
qdisc_hash_add(cl->qdisc, true);
INIT_LIST_HEAD(&cl->children);
cl->vt_tree = RB_ROOT;
cl->cf_tree = RB_ROOT;
Expand Down Expand Up @@ -1425,6 +1427,8 @@ hfsc_init_qdisc(struct Qdisc *sch, struct nlattr *opt)
sch->handle);
if (q->root.qdisc == NULL)
q->root.qdisc = &noop_qdisc;
else
qdisc_hash_add(q->root.qdisc, true);
INIT_LIST_HEAD(&q->root.children);
q->root.vt_tree = RB_ROOT;
q->root.cf_tree = RB_ROOT;
Expand Down
2 changes: 2 additions & 0 deletions net/sched/sch_htb.c
Original file line number Diff line number Diff line change
Expand Up @@ -1460,6 +1460,8 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
qdisc_class_hash_insert(&q->clhash, &cl->common);
if (parent)
parent->children++;
if (cl->un.leaf.q != &noop_qdisc)
qdisc_hash_add(cl->un.leaf.q, true);
} else {
if (tca[TCA_RATE]) {
err = gen_replace_estimator(&cl->bstats, NULL,
Expand Down
2 changes: 1 addition & 1 deletion net/sched/sch_mq.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ static void mq_attach(struct Qdisc *sch)
qdisc_destroy(old);
#ifdef CONFIG_NET_SCHED
if (ntx < dev->real_num_tx_queues)
qdisc_hash_add(qdisc);
qdisc_hash_add(qdisc, false);
#endif

}
Expand Down
2 changes: 1 addition & 1 deletion net/sched/sch_mqprio.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ static void mqprio_attach(struct Qdisc *sch)
if (old)
qdisc_destroy(old);
if (ntx < dev->real_num_tx_queues)
qdisc_hash_add(qdisc);
qdisc_hash_add(qdisc, false);
}
kfree(priv->qdiscs);
priv->qdiscs = NULL;
Expand Down
2 changes: 2 additions & 0 deletions net/sched/sch_multiq.c
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,8 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt)
sch_tree_lock(sch);
old = q->queues[i];
q->queues[i] = child;
if (child != &noop_qdisc)
qdisc_hash_add(child, true);

if (old != &noop_qdisc) {
qdisc_tree_reduce_backlog(old,
Expand Down
5 changes: 4 additions & 1 deletion net/sched/sch_prio.c
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,11 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt)
qdisc_destroy(child);
}

for (i = oldbands; i < q->bands; i++)
for (i = oldbands; i < q->bands; i++) {
q->queues[i] = queues[i];
if (q->queues[i] != &noop_qdisc)
qdisc_hash_add(q->queues[i], true);
}

sch_tree_unlock(sch);
return 0;
Expand Down
2 changes: 2 additions & 0 deletions net/sched/sch_qfq.c
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,8 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
goto destroy_class;
}

if (cl->qdisc != &noop_qdisc)
qdisc_hash_add(cl->qdisc, true);
sch_tree_lock(sch);
qdisc_class_hash_insert(&q->clhash, &cl->common);
sch_tree_unlock(sch);
Expand Down
2 changes: 2 additions & 0 deletions net/sched/sch_red.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ static int red_change(struct Qdisc *sch, struct nlattr *opt)
return PTR_ERR(child);
}

if (child != &noop_qdisc)
qdisc_hash_add(child, true);
sch_tree_lock(sch);
q->flags = ctl->flags;
q->limit = ctl->limit;
Expand Down
2 changes: 2 additions & 0 deletions net/sched/sch_sfb.c
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,8 @@ static int sfb_change(struct Qdisc *sch, struct nlattr *opt)
if (IS_ERR(child))
return PTR_ERR(child);

if (child != &noop_qdisc)
qdisc_hash_add(child, true);
sch_tree_lock(sch);

qdisc_tree_reduce_backlog(q->qdisc, q->qdisc->q.qlen,
Expand Down
2 changes: 2 additions & 0 deletions net/sched/sch_tbf.c
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,8 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt)
q->qdisc->qstats.backlog);
qdisc_destroy(q->qdisc);
q->qdisc = child;
if (child != &noop_qdisc);
qdisc_hash_add(child, true);
}
q->limit = qopt->limit;
if (tb[TCA_TBF_PBURST])
Expand Down

0 comments on commit 49b4997

Please sign in to comment.