net: sch: api: add extack support in qdisc_create_dflt

This patch adds extack support for the function qdisc_create_dflt which is
a common used function in the tc subsystem. Callers which are interested
in the receiving error can assign extack to get a more detailed
information why qdisc_create_dflt failed. The function qdisc_create_dflt
will also call an init callback which can fail by any per-qdisc specific
handling.

Cc: David Ahern <dsahern@gmail.com>
Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: Alexander Aring <aring@mojatatu.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Alexander Aring 2017-12-20 12:35:21 -05:00 committed by David S. Miller
parent d0bd684ddd
commit a38a98821c
18 changed files with 56 additions and 40 deletions

View File

@ -89,7 +89,8 @@ extern struct Qdisc_ops pfifo_head_drop_qdisc_ops;
int fifo_set_limit(struct Qdisc *q, unsigned int limit); int fifo_set_limit(struct Qdisc *q, unsigned int limit);
struct Qdisc *fifo_create_dflt(struct Qdisc *sch, struct Qdisc_ops *ops, struct Qdisc *fifo_create_dflt(struct Qdisc *sch, struct Qdisc_ops *ops,
unsigned int limit); unsigned int limit,
struct netlink_ext_ack *extack);
int register_qdisc(struct Qdisc_ops *qops); int register_qdisc(struct Qdisc_ops *qops);
int unregister_qdisc(struct Qdisc_ops *qops); int unregister_qdisc(struct Qdisc_ops *qops);

View File

@ -474,7 +474,8 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
const struct Qdisc_ops *ops, const struct Qdisc_ops *ops,
struct netlink_ext_ack *extack); struct netlink_ext_ack *extack);
struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue, struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue,
const struct Qdisc_ops *ops, u32 parentid); const struct Qdisc_ops *ops, u32 parentid,
struct netlink_ext_ack *extack);
void __qdisc_calculate_pkt_len(struct sk_buff *skb, void __qdisc_calculate_pkt_len(struct sk_buff *skb,
const struct qdisc_size_table *stab); const struct qdisc_size_table *stab);
int skb_do_redirect(struct sk_buff *); int skb_do_redirect(struct sk_buff *);

View File

@ -290,7 +290,8 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent,
goto err_out; goto err_out;
} }
flow->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, classid); flow->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, classid,
extack);
if (!flow->q) if (!flow->q)
flow->q = &noop_qdisc; flow->q = &noop_qdisc;
pr_debug("atm_tc_change: qdisc %p\n", flow->q); pr_debug("atm_tc_change: qdisc %p\n", flow->q);
@ -546,7 +547,7 @@ static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt,
INIT_LIST_HEAD(&p->link.list); INIT_LIST_HEAD(&p->link.list);
list_add(&p->link.list, &p->flows); list_add(&p->link.list, &p->flows);
p->link.q = qdisc_create_dflt(sch->dev_queue, p->link.q = qdisc_create_dflt(sch->dev_queue,
&pfifo_qdisc_ops, sch->handle); &pfifo_qdisc_ops, sch->handle, extack);
if (!p->link.q) if (!p->link.q)
p->link.q = &noop_qdisc; p->link.q = &noop_qdisc;
pr_debug("atm_tc_init: link (%p) qdisc %p\n", &p->link, p->link.q); pr_debug("atm_tc_init: link (%p) qdisc %p\n", &p->link, p->link.q);

View File

@ -1172,7 +1172,7 @@ static int cbq_init(struct Qdisc *sch, struct nlattr *opt,
q->link.common.classid = sch->handle; q->link.common.classid = sch->handle;
q->link.qdisc = sch; q->link.qdisc = sch;
q->link.q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, q->link.q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
sch->handle); sch->handle, NULL);
if (!q->link.q) if (!q->link.q)
q->link.q = &noop_qdisc; q->link.q = &noop_qdisc;
else else
@ -1376,8 +1376,8 @@ static int cbq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
struct cbq_class *cl = (struct cbq_class *)arg; struct cbq_class *cl = (struct cbq_class *)arg;
if (new == NULL) { if (new == NULL) {
new = qdisc_create_dflt(sch->dev_queue, new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
&pfifo_qdisc_ops, cl->common.classid); cl->common.classid, extack);
if (new == NULL) if (new == NULL)
return -ENOBUFS; return -ENOBUFS;
} }
@ -1596,7 +1596,8 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
cl->R_tab = rtab; cl->R_tab = rtab;
rtab = NULL; rtab = NULL;
cl->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, classid); cl->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, classid,
NULL);
if (!cl->q) if (!cl->q)
cl->q = &noop_qdisc; cl->q = &noop_qdisc;
else else

View File

@ -114,7 +114,8 @@ static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
cl->common.classid = classid; cl->common.classid = classid;
cl->quantum = quantum; cl->quantum = quantum;
cl->qdisc = qdisc_create_dflt(sch->dev_queue, cl->qdisc = qdisc_create_dflt(sch->dev_queue,
&pfifo_qdisc_ops, classid); &pfifo_qdisc_ops, classid,
NULL);
if (cl->qdisc == NULL) if (cl->qdisc == NULL)
cl->qdisc = &noop_qdisc; cl->qdisc = &noop_qdisc;
else else
@ -209,8 +210,8 @@ static int drr_graft_class(struct Qdisc *sch, unsigned long arg,
struct drr_class *cl = (struct drr_class *)arg; struct drr_class *cl = (struct drr_class *)arg;
if (new == NULL) { if (new == NULL) {
new = qdisc_create_dflt(sch->dev_queue, new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
&pfifo_qdisc_ops, cl->common.classid); cl->common.classid, NULL);
if (new == NULL) if (new == NULL)
new = &noop_qdisc; new = &noop_qdisc;
} }

View File

@ -71,7 +71,7 @@ static int dsmark_graft(struct Qdisc *sch, unsigned long arg,
if (new == NULL) { if (new == NULL) {
new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
sch->handle); sch->handle, NULL);
if (new == NULL) if (new == NULL)
new = &noop_qdisc; new = &noop_qdisc;
} }
@ -381,7 +381,8 @@ static int dsmark_init(struct Qdisc *sch, struct nlattr *opt,
p->default_index = default_index; p->default_index = default_index;
p->set_tc_index = nla_get_flag(tb[TCA_DSMARK_SET_TC_INDEX]); p->set_tc_index = nla_get_flag(tb[TCA_DSMARK_SET_TC_INDEX]);
p->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, sch->handle); p->q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, sch->handle,
NULL);
if (p->q == NULL) if (p->q == NULL)
p->q = &noop_qdisc; p->q = &noop_qdisc;
else else

View File

@ -166,12 +166,14 @@ int fifo_set_limit(struct Qdisc *q, unsigned int limit)
EXPORT_SYMBOL(fifo_set_limit); EXPORT_SYMBOL(fifo_set_limit);
struct Qdisc *fifo_create_dflt(struct Qdisc *sch, struct Qdisc_ops *ops, struct Qdisc *fifo_create_dflt(struct Qdisc *sch, struct Qdisc_ops *ops,
unsigned int limit) unsigned int limit,
struct netlink_ext_ack *extack)
{ {
struct Qdisc *q; struct Qdisc *q;
int err = -ENOMEM; int err = -ENOMEM;
q = qdisc_create_dflt(sch->dev_queue, ops, TC_H_MAKE(sch->handle, 1)); q = qdisc_create_dflt(sch->dev_queue, ops, TC_H_MAKE(sch->handle, 1),
extack);
if (q) { if (q) {
err = fifo_set_limit(q, limit); err = fifo_set_limit(q, limit);
if (err < 0) { if (err < 0) {

View File

@ -830,21 +830,24 @@ errout:
struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue, struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue,
const struct Qdisc_ops *ops, const struct Qdisc_ops *ops,
unsigned int parentid) unsigned int parentid,
struct netlink_ext_ack *extack)
{ {
struct Qdisc *sch; struct Qdisc *sch;
if (!try_module_get(ops->owner)) if (!try_module_get(ops->owner)) {
NL_SET_ERR_MSG(extack, "Failed to increase module reference counter");
return NULL; return NULL;
}
sch = qdisc_alloc(dev_queue, ops, NULL); sch = qdisc_alloc(dev_queue, ops, extack);
if (IS_ERR(sch)) { if (IS_ERR(sch)) {
module_put(ops->owner); module_put(ops->owner);
return NULL; return NULL;
} }
sch->parent = parentid; sch->parent = parentid;
if (!ops->init || ops->init(sch, NULL, NULL) == 0) if (!ops->init || ops->init(sch, NULL, extack) == 0)
return sch; return sch;
qdisc_destroy(sch); qdisc_destroy(sch);
@ -956,7 +959,7 @@ static void attach_one_default_qdisc(struct net_device *dev,
if (dev->priv_flags & IFF_NO_QUEUE) if (dev->priv_flags & IFF_NO_QUEUE)
ops = &noqueue_qdisc_ops; ops = &noqueue_qdisc_ops;
qdisc = qdisc_create_dflt(dev_queue, ops, TC_H_ROOT); qdisc = qdisc_create_dflt(dev_queue, ops, TC_H_ROOT, NULL);
if (!qdisc) { if (!qdisc) {
netdev_info(dev, "activation failed\n"); netdev_info(dev, "activation failed\n");
return; return;
@ -979,7 +982,7 @@ static void attach_default_qdiscs(struct net_device *dev)
dev->qdisc = txq->qdisc_sleeping; dev->qdisc = txq->qdisc_sleeping;
qdisc_refcount_inc(dev->qdisc); qdisc_refcount_inc(dev->qdisc);
} else { } else {
qdisc = qdisc_create_dflt(txq, &mq_qdisc_ops, TC_H_ROOT); qdisc = qdisc_create_dflt(txq, &mq_qdisc_ops, TC_H_ROOT, NULL);
if (qdisc) { if (qdisc) {
dev->qdisc = qdisc; dev->qdisc = qdisc;
qdisc->ops->attach(qdisc); qdisc->ops->attach(qdisc);

View File

@ -1062,8 +1062,8 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
cl->cl_common.classid = classid; cl->cl_common.classid = classid;
cl->sched = q; cl->sched = q;
cl->cl_parent = parent; cl->cl_parent = parent;
cl->qdisc = qdisc_create_dflt(sch->dev_queue, cl->qdisc = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
&pfifo_qdisc_ops, classid); classid, NULL);
if (cl->qdisc == NULL) if (cl->qdisc == NULL)
cl->qdisc = &noop_qdisc; cl->qdisc = &noop_qdisc;
else else
@ -1185,7 +1185,7 @@ hfsc_graft_class(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
return -EINVAL; return -EINVAL;
if (new == NULL) { if (new == NULL) {
new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
cl->cl_common.classid); cl->cl_common.classid, NULL);
if (new == NULL) if (new == NULL)
new = &noop_qdisc; new = &noop_qdisc;
} }
@ -1416,7 +1416,7 @@ hfsc_init_qdisc(struct Qdisc *sch, struct nlattr *opt,
q->root.cl_common.classid = sch->handle; q->root.cl_common.classid = sch->handle;
q->root.sched = q; q->root.sched = q;
q->root.qdisc = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, q->root.qdisc = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
sch->handle); sch->handle, NULL);
if (q->root.qdisc == NULL) if (q->root.qdisc == NULL)
q->root.qdisc = &noop_qdisc; q->root.qdisc = &noop_qdisc;
else else

View File

@ -1180,7 +1180,7 @@ static int htb_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
return -EINVAL; return -EINVAL;
if (new == NULL && if (new == NULL &&
(new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, (new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
cl->common.classid)) == NULL) cl->common.classid, extack)) == NULL)
return -ENOBUFS; return -ENOBUFS;
*old = qdisc_replace(sch, new, &cl->un.leaf.q); *old = qdisc_replace(sch, new, &cl->un.leaf.q);
@ -1290,7 +1290,8 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg)
if (!cl->level && htb_parent_last_child(cl)) { if (!cl->level && htb_parent_last_child(cl)) {
new_q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, new_q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
cl->parent->common.classid); cl->parent->common.classid,
NULL);
last_child = 1; last_child = 1;
} }
@ -1426,8 +1427,8 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
* so that can't be used inside of sch_tree_lock * so that can't be used inside of sch_tree_lock
* -- thanks to Karlis Peisenieks * -- thanks to Karlis Peisenieks
*/ */
new_q = qdisc_create_dflt(sch->dev_queue, new_q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
&pfifo_qdisc_ops, classid); classid, NULL);
sch_tree_lock(sch); sch_tree_lock(sch);
if (parent && !parent->level) { if (parent && !parent->level) {
unsigned int qlen = parent->un.leaf.q->q.qlen; unsigned int qlen = parent->un.leaf.q->q.qlen;

View File

@ -61,7 +61,8 @@ static int mq_init(struct Qdisc *sch, struct nlattr *opt,
dev_queue = netdev_get_tx_queue(dev, ntx); dev_queue = netdev_get_tx_queue(dev, ntx);
qdisc = qdisc_create_dflt(dev_queue, get_default_qdisc_ops(dev, ntx), qdisc = qdisc_create_dflt(dev_queue, get_default_qdisc_ops(dev, ntx),
TC_H_MAKE(TC_H_MAJ(sch->handle), TC_H_MAKE(TC_H_MAJ(sch->handle),
TC_H_MIN(ntx + 1))); TC_H_MIN(ntx + 1)),
extack);
if (!qdisc) if (!qdisc)
return -ENOMEM; return -ENOMEM;
priv->qdiscs[ntx] = qdisc; priv->qdiscs[ntx] = qdisc;

View File

@ -230,7 +230,7 @@ static int mqprio_init(struct Qdisc *sch, struct nlattr *opt,
qdisc = qdisc_create_dflt(dev_queue, qdisc = qdisc_create_dflt(dev_queue,
get_default_qdisc_ops(dev, i), get_default_qdisc_ops(dev, i),
TC_H_MAKE(TC_H_MAJ(sch->handle), TC_H_MAKE(TC_H_MAJ(sch->handle),
TC_H_MIN(i + 1))); TC_H_MIN(i + 1)), extack);
if (!qdisc) if (!qdisc)
return -ENOMEM; return -ENOMEM;

View File

@ -216,7 +216,7 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt,
child = qdisc_create_dflt(sch->dev_queue, child = qdisc_create_dflt(sch->dev_queue,
&pfifo_qdisc_ops, &pfifo_qdisc_ops,
TC_H_MAKE(sch->handle, TC_H_MAKE(sch->handle,
i + 1)); i + 1), extack);
if (child) { if (child) {
sch_tree_lock(sch); sch_tree_lock(sch);
old = q->queues[i]; old = q->queues[i];

View File

@ -176,7 +176,8 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt,
/* Before commit, make sure we can allocate all new qdiscs */ /* Before commit, make sure we can allocate all new qdiscs */
for (i = oldbands; i < qopt->bands; i++) { for (i = oldbands; i < qopt->bands; i++) {
queues[i] = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, queues[i] = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
TC_H_MAKE(sch->handle, i + 1)); TC_H_MAKE(sch->handle, i + 1),
extack);
if (!queues[i]) { if (!queues[i]) {
while (i > oldbands) while (i > oldbands)
qdisc_destroy(queues[--i]); qdisc_destroy(queues[--i]);

View File

@ -480,8 +480,8 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
cl->common.classid = classid; cl->common.classid = classid;
cl->deficit = lmax; cl->deficit = lmax;
cl->qdisc = qdisc_create_dflt(sch->dev_queue, cl->qdisc = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
&pfifo_qdisc_ops, classid); classid, NULL);
if (cl->qdisc == NULL) if (cl->qdisc == NULL)
cl->qdisc = &noop_qdisc; cl->qdisc = &noop_qdisc;
@ -601,8 +601,8 @@ static int qfq_graft_class(struct Qdisc *sch, unsigned long arg,
struct qfq_class *cl = (struct qfq_class *)arg; struct qfq_class *cl = (struct qfq_class *)arg;
if (new == NULL) { if (new == NULL) {
new = qdisc_create_dflt(sch->dev_queue, new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops,
&pfifo_qdisc_ops, cl->common.classid); cl->common.classid, NULL);
if (new == NULL) if (new == NULL)
new = &noop_qdisc; new = &noop_qdisc;
} }

View File

@ -225,7 +225,8 @@ static int red_change(struct Qdisc *sch, struct nlattr *opt,
return -EINVAL; return -EINVAL;
if (ctl->limit > 0) { if (ctl->limit > 0) {
child = fifo_create_dflt(sch, &bfifo_qdisc_ops, ctl->limit); child = fifo_create_dflt(sch, &bfifo_qdisc_ops, ctl->limit,
extack);
if (IS_ERR(child)) if (IS_ERR(child))
return PTR_ERR(child); return PTR_ERR(child);
} }

View File

@ -513,7 +513,7 @@ static int sfb_change(struct Qdisc *sch, struct nlattr *opt,
if (limit == 0) if (limit == 0)
limit = qdisc_dev(sch)->tx_queue_len; limit = qdisc_dev(sch)->tx_queue_len;
child = fifo_create_dflt(sch, &pfifo_qdisc_ops, limit); child = fifo_create_dflt(sch, &pfifo_qdisc_ops, limit, extack);
if (IS_ERR(child)) if (IS_ERR(child))
return PTR_ERR(child); return PTR_ERR(child);

View File

@ -386,7 +386,8 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt,
if (err) if (err)
goto done; goto done;
} else if (qopt->limit > 0) { } else if (qopt->limit > 0) {
child = fifo_create_dflt(sch, &bfifo_qdisc_ops, qopt->limit); child = fifo_create_dflt(sch, &bfifo_qdisc_ops, qopt->limit,
extack);
if (IS_ERR(child)) { if (IS_ERR(child)) {
err = PTR_ERR(child); err = PTR_ERR(child);
goto done; goto done;