From ac8ef4ab731fae8617a41960917ceda475d5a2df Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 20 Dec 2017 12:35:11 -0500 Subject: [PATCH 01/14] net: sched: fix coding style issues This patch fix checkpatch issues for upcomming patches according to the sched api file. It changes mostly how to check on null pointer. Acked-by: Jamal Hadi Salim Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- net/sched/sch_api.c | 2 +- net/sched/sch_cbq.c | 12 ++++++------ net/sched/sch_gred.c | 7 ++++--- net/sched/sch_hfsc.c | 2 +- net/sched/sch_multiq.c | 2 +- net/sched/sch_tbf.c | 2 +- 6 files changed, 14 insertions(+), 13 deletions(-) diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 74c22b4e365e..96a5e5d9378e 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -669,7 +669,7 @@ int qdisc_class_hash_init(struct Qdisc_class_hash *clhash) unsigned int size = 4; clhash->hash = qdisc_class_hash_alloc(size); - if (clhash->hash == NULL) + if (!clhash->hash) return -ENOMEM; clhash->hashsize = size; clhash->hashmask = size - 1; diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index 525eb3a6d625..0692fe35f4ec 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -1150,12 +1150,13 @@ static int cbq_init(struct Qdisc *sch, struct nlattr *opt) if (err < 0) return err; - if (tb[TCA_CBQ_RTAB] == NULL || tb[TCA_CBQ_RATE] == NULL) + if (!tb[TCA_CBQ_RTAB] || !tb[TCA_CBQ_RATE]) return -EINVAL; r = nla_data(tb[TCA_CBQ_RATE]); - if ((q->link.R_tab = qdisc_get_rtab(r, tb[TCA_CBQ_RTAB])) == NULL) + q->link.R_tab = qdisc_get_rtab(r, tb[TCA_CBQ_RTAB]); + if (!q->link.R_tab) return -EINVAL; err = tcf_block_get(&q->link.block, &q->link.filter_list, sch); @@ -1460,7 +1461,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t struct cbq_class *parent; struct qdisc_rate_table *rtab = NULL; - if (opt == NULL) + if (!opt) return -EINVAL; err = nla_parse_nested(tb, TCA_CBQ_MAX, opt, cbq_policy, NULL); @@ -1532,8 +1533,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t if (parentid == TC_H_ROOT) return -EINVAL; - if (tb[TCA_CBQ_WRROPT] == NULL || tb[TCA_CBQ_RATE] == NULL || - tb[TCA_CBQ_LSSOPT] == NULL) + if (!tb[TCA_CBQ_WRROPT] || !tb[TCA_CBQ_RATE] || !tb[TCA_CBQ_LSSOPT]) return -EINVAL; rtab = qdisc_get_rtab(nla_data(tb[TCA_CBQ_RATE]), tb[TCA_CBQ_RTAB]); @@ -1565,7 +1565,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t if (parentid) { parent = cbq_class_lookup(q, parentid); err = -EINVAL; - if (parent == NULL) + if (!parent) goto failure; } diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c index bc30f9186ac6..ccd1a00e2a9a 100644 --- a/net/sched/sch_gred.c +++ b/net/sched/sch_gred.c @@ -306,12 +306,13 @@ static inline int gred_change_table_def(struct Qdisc *sch, struct nlattr *dps) struct tc_gred_sopt *sopt; int i; - if (dps == NULL) + if (!dps) return -EINVAL; sopt = nla_data(dps); - if (sopt->DPs > MAX_DPs || sopt->DPs == 0 || sopt->def_DP >= sopt->DPs) + if (sopt->DPs > MAX_DPs || sopt->DPs == 0 || + sopt->def_DP >= sopt->DPs) return -EINVAL; sch_tree_lock(sch); @@ -470,7 +471,7 @@ static int gred_init(struct Qdisc *sch, struct nlattr *opt) struct nlattr *tb[TCA_GRED_MAX + 1]; int err; - if (opt == NULL) + if (!opt) return -EINVAL; err = nla_parse_nested(tb, TCA_GRED_MAX, opt, gred_policy, NULL); diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index d04068a97d81..94db20352f37 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -1396,7 +1396,7 @@ hfsc_init_qdisc(struct Qdisc *sch, struct nlattr *opt) qdisc_watchdog_init(&q->watchdog, sch); - if (opt == NULL || nla_len(opt) < sizeof(*qopt)) + if (!opt || nla_len(opt) < sizeof(*qopt)) return -EINVAL; qopt = nla_data(opt); diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c index 012216386c0b..37195e0c64ba 100644 --- a/net/sched/sch_multiq.c +++ b/net/sched/sch_multiq.c @@ -243,7 +243,7 @@ static int multiq_init(struct Qdisc *sch, struct nlattr *opt) q->queues = NULL; - if (opt == NULL) + if (!opt) return -EINVAL; err = tcf_block_get(&q->block, &q->filter_list, sch); diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index 120f4f365967..e8f3345674c5 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c @@ -428,7 +428,7 @@ static int tbf_init(struct Qdisc *sch, struct nlattr *opt) qdisc_watchdog_init(&q->watchdog, sch); q->qdisc = &noop_qdisc; - if (opt == NULL) + if (!opt) return -EINVAL; q->t_c = ktime_get_ns(); From 09215598119ebf89bd204ca4ad8b7059266053d9 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 20 Dec 2017 12:35:12 -0500 Subject: [PATCH 02/14] net: sched: sch_api: handle generic qdisc errors This patch adds extack support for generic qdisc handling. The extack will be set deeper to each called function which is not part of netdev core api. Cc: David Ahern Acked-by: Jamal Hadi Salim Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- net/sched/sch_api.c | 148 +++++++++++++++++++++++++++++++------------- 1 file changed, 105 insertions(+), 43 deletions(-) diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 96a5e5d9378e..954c0fc45473 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -449,7 +449,8 @@ static const struct nla_policy stab_policy[TCA_STAB_MAX + 1] = { [TCA_STAB_DATA] = { .type = NLA_BINARY }, }; -static struct qdisc_size_table *qdisc_get_stab(struct nlattr *opt) +static struct qdisc_size_table *qdisc_get_stab(struct nlattr *opt, + struct netlink_ext_ack *extack) { struct nlattr *tb[TCA_STAB_MAX + 1]; struct qdisc_size_table *stab; @@ -458,23 +459,29 @@ static struct qdisc_size_table *qdisc_get_stab(struct nlattr *opt) u16 *tab = NULL; int err; - err = nla_parse_nested(tb, TCA_STAB_MAX, opt, stab_policy, NULL); + err = nla_parse_nested(tb, TCA_STAB_MAX, opt, stab_policy, extack); if (err < 0) return ERR_PTR(err); - if (!tb[TCA_STAB_BASE]) + if (!tb[TCA_STAB_BASE]) { + NL_SET_ERR_MSG(extack, "Size table base attribute is missing"); return ERR_PTR(-EINVAL); + } s = nla_data(tb[TCA_STAB_BASE]); if (s->tsize > 0) { - if (!tb[TCA_STAB_DATA]) + if (!tb[TCA_STAB_DATA]) { + NL_SET_ERR_MSG(extack, "Size table data attribute is missing"); return ERR_PTR(-EINVAL); + } tab = nla_data(tb[TCA_STAB_DATA]); tsize = nla_len(tb[TCA_STAB_DATA]) / sizeof(u16); } - if (tsize != s->tsize || (!tab && tsize > 0)) + if (tsize != s->tsize || (!tab && tsize > 0)) { + NL_SET_ERR_MSG(extack, "Invalid size of size table"); return ERR_PTR(-EINVAL); + } list_for_each_entry(stab, &qdisc_stab_list, list) { if (memcmp(&stab->szopts, s, sizeof(*s))) @@ -899,7 +906,8 @@ static void notify_and_destroy(struct net *net, struct sk_buff *skb, static int qdisc_graft(struct net_device *dev, struct Qdisc *parent, struct sk_buff *skb, struct nlmsghdr *n, u32 classid, - struct Qdisc *new, struct Qdisc *old) + struct Qdisc *new, struct Qdisc *old, + struct netlink_ext_ack *extack) { struct Qdisc *q = old; struct net *net = dev_net(dev); @@ -914,8 +922,10 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent, (new && new->flags & TCQ_F_INGRESS)) { num_q = 1; ingress = 1; - if (!dev_ingress_queue(dev)) + if (!dev_ingress_queue(dev)) { + NL_SET_ERR_MSG(extack, "Device does not have an ingress queue"); return -ENOENT; + } } if (dev->flags & IFF_UP) @@ -966,10 +976,12 @@ skip: if (cops && cops->graft) { unsigned long cl = cops->find(parent, classid); - if (cl) + if (cl) { err = cops->graft(parent, cl, new, &old); - else + } else { + NL_SET_ERR_MSG(extack, "Specified class not found"); err = -ENOENT; + } } if (!err) notify_and_destroy(net, skb, n, classid, old, new); @@ -990,7 +1002,8 @@ static struct lock_class_key qdisc_rx_lock; static struct Qdisc *qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue, struct Qdisc *p, u32 parent, u32 handle, - struct nlattr **tca, int *errp) + struct nlattr **tca, int *errp, + struct netlink_ext_ack *extack) { int err; struct nlattr *kind = tca[TCA_KIND]; @@ -1028,8 +1041,10 @@ static struct Qdisc *qdisc_create(struct net_device *dev, #endif err = -ENOENT; - if (!ops) + if (!ops) { + NL_SET_ERR_MSG(extack, "Specified qdisc not found"); goto err_out; + } sch = qdisc_alloc(dev_queue, ops); if (IS_ERR(sch)) { @@ -1086,7 +1101,7 @@ static struct Qdisc *qdisc_create(struct net_device *dev, } if (tca[TCA_STAB]) { - stab = qdisc_get_stab(tca[TCA_STAB]); + stab = qdisc_get_stab(tca[TCA_STAB], extack); if (IS_ERR(stab)) { err = PTR_ERR(stab); goto err_out4; @@ -1097,8 +1112,10 @@ static struct Qdisc *qdisc_create(struct net_device *dev, seqcount_t *running; err = -EOPNOTSUPP; - if (sch->flags & TCQ_F_MQROOT) + if (sch->flags & TCQ_F_MQROOT) { + NL_SET_ERR_MSG(extack, "Cannot attach rate estimator to a multi-queue root qdisc"); goto err_out4; + } if (sch->parent != TC_H_ROOT && !(sch->flags & TCQ_F_INGRESS) && @@ -1113,8 +1130,10 @@ static struct Qdisc *qdisc_create(struct net_device *dev, NULL, running, tca[TCA_RATE]); - if (err) + if (err) { + NL_SET_ERR_MSG(extack, "Failed to generate new estimator"); goto err_out4; + } } qdisc_hash_add(sch, false); @@ -1147,21 +1166,24 @@ err_out4: goto err_out3; } -static int qdisc_change(struct Qdisc *sch, struct nlattr **tca) +static int qdisc_change(struct Qdisc *sch, struct nlattr **tca, + struct netlink_ext_ack *extack) { struct qdisc_size_table *ostab, *stab = NULL; int err = 0; if (tca[TCA_OPTIONS]) { - if (!sch->ops->change) + if (!sch->ops->change) { + NL_SET_ERR_MSG(extack, "Change operation not supported by specified qdisc"); return -EINVAL; + } err = sch->ops->change(sch, tca[TCA_OPTIONS]); if (err) return err; } if (tca[TCA_STAB]) { - stab = qdisc_get_stab(tca[TCA_STAB]); + stab = qdisc_get_stab(tca[TCA_STAB], extack); if (IS_ERR(stab)) return PTR_ERR(stab); } @@ -1259,8 +1281,10 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, if (clid != TC_H_ROOT) { if (TC_H_MAJ(clid) != TC_H_MAJ(TC_H_INGRESS)) { p = qdisc_lookup(dev, TC_H_MAJ(clid)); - if (!p) + if (!p) { + NL_SET_ERR_MSG(extack, "Failed to find qdisc with specified classid"); return -ENOENT; + } q = qdisc_leaf(p, clid); } else if (dev_ingress_queue(dev)) { q = dev_ingress_queue(dev)->qdisc_sleeping; @@ -1268,26 +1292,38 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, } else { q = dev->qdisc; } - if (!q) + if (!q) { + NL_SET_ERR_MSG(extack, "Cannot find specified qdisc on specified device"); return -ENOENT; + } - if (tcm->tcm_handle && q->handle != tcm->tcm_handle) + if (tcm->tcm_handle && q->handle != tcm->tcm_handle) { + NL_SET_ERR_MSG(extack, "Invalid handle"); return -EINVAL; + } } else { q = qdisc_lookup(dev, tcm->tcm_handle); - if (!q) + if (!q) { + NL_SET_ERR_MSG(extack, "Failed to find qdisc with specified handle"); return -ENOENT; + } } - if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], q->ops->id)) + if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], q->ops->id)) { + NL_SET_ERR_MSG(extack, "Invalid qdisc name"); return -EINVAL; + } if (n->nlmsg_type == RTM_DELQDISC) { - if (!clid) + if (!clid) { + NL_SET_ERR_MSG(extack, "Classid cannot be zero"); return -EINVAL; - if (q->handle == 0) + } + if (q->handle == 0) { + NL_SET_ERR_MSG(extack, "Cannot delete qdisc with handle of zero"); return -ENOENT; - err = qdisc_graft(dev, p, skb, n, clid, NULL, q); + } + err = qdisc_graft(dev, p, skb, n, clid, NULL, q, extack); if (err != 0) return err; } else { @@ -1333,8 +1369,10 @@ replay: if (clid != TC_H_ROOT) { if (clid != TC_H_INGRESS) { p = qdisc_lookup(dev, TC_H_MAJ(clid)); - if (!p) + if (!p) { + NL_SET_ERR_MSG(extack, "Failed to find specified qdisc"); return -ENOENT; + } q = qdisc_leaf(p, clid); } else if (dev_ingress_queue_create(dev)) { q = dev_ingress_queue(dev)->qdisc_sleeping; @@ -1349,21 +1387,33 @@ replay: if (!q || !tcm->tcm_handle || q->handle != tcm->tcm_handle) { if (tcm->tcm_handle) { - if (q && !(n->nlmsg_flags & NLM_F_REPLACE)) + if (q && !(n->nlmsg_flags & NLM_F_REPLACE)) { + NL_SET_ERR_MSG(extack, "NLM_F_REPLACE needed to override"); return -EEXIST; - if (TC_H_MIN(tcm->tcm_handle)) + } + if (TC_H_MIN(tcm->tcm_handle)) { + NL_SET_ERR_MSG(extack, "Invalid minor handle"); return -EINVAL; + } q = qdisc_lookup(dev, tcm->tcm_handle); - if (!q) + if (!q) { + NL_SET_ERR_MSG(extack, "No qdisc found for specified handle"); goto create_n_graft; - if (n->nlmsg_flags & NLM_F_EXCL) + } + if (n->nlmsg_flags & NLM_F_EXCL) { + NL_SET_ERR_MSG(extack, "Exclusivity flag on, cannot override"); return -EEXIST; + } if (tca[TCA_KIND] && - nla_strcmp(tca[TCA_KIND], q->ops->id)) + nla_strcmp(tca[TCA_KIND], q->ops->id)) { + NL_SET_ERR_MSG(extack, "Invalid qdisc name"); return -EINVAL; + } if (q == p || - (p && check_loop(q, p, 0))) + (p && check_loop(q, p, 0))) { + NL_SET_ERR_MSG(extack, "Qdisc parent/child loop detected"); return -ELOOP; + } qdisc_refcount_inc(q); goto graft; } else { @@ -1398,33 +1448,45 @@ replay: } } } else { - if (!tcm->tcm_handle) + if (!tcm->tcm_handle) { + NL_SET_ERR_MSG(extack, "Handle cannot be zero"); return -EINVAL; + } q = qdisc_lookup(dev, tcm->tcm_handle); } /* Change qdisc parameters */ - if (!q) + if (!q) { + NL_SET_ERR_MSG(extack, "Specified qdisc not found"); return -ENOENT; - if (n->nlmsg_flags & NLM_F_EXCL) + } + if (n->nlmsg_flags & NLM_F_EXCL) { + NL_SET_ERR_MSG(extack, "Exclusivity flag on, cannot modify"); return -EEXIST; - if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], q->ops->id)) + } + if (tca[TCA_KIND] && nla_strcmp(tca[TCA_KIND], q->ops->id)) { + NL_SET_ERR_MSG(extack, "Invalid qdisc name"); return -EINVAL; - err = qdisc_change(q, tca); + } + err = qdisc_change(q, tca, extack); if (err == 0) qdisc_notify(net, skb, n, clid, NULL, q); return err; create_n_graft: - if (!(n->nlmsg_flags & NLM_F_CREATE)) + if (!(n->nlmsg_flags & NLM_F_CREATE)) { + NL_SET_ERR_MSG(extack, "Qdisc not found. To create specify NLM_F_CREATE flag"); return -ENOENT; + } if (clid == TC_H_INGRESS) { - if (dev_ingress_queue(dev)) + if (dev_ingress_queue(dev)) { q = qdisc_create(dev, dev_ingress_queue(dev), p, tcm->tcm_parent, tcm->tcm_parent, - tca, &err); - else + tca, &err, extack); + } else { + NL_SET_ERR_MSG(extack, "Cannot find ingress queue for specified device"); err = -ENOENT; + } } else { struct netdev_queue *dev_queue; @@ -1437,7 +1499,7 @@ create_n_graft: q = qdisc_create(dev, dev_queue, p, tcm->tcm_parent, tcm->tcm_handle, - tca, &err); + tca, &err, extack); } if (q == NULL) { if (err == -EAGAIN) @@ -1446,7 +1508,7 @@ create_n_graft: } graft: - err = qdisc_graft(dev, p, skb, n, clid, q, NULL); + err = qdisc_graft(dev, p, skb, n, clid, q, NULL, extack); if (err) { if (q) qdisc_destroy(q); From e63d7dfd2df7aa204849599c6f378e627e926657 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 20 Dec 2017 12:35:13 -0500 Subject: [PATCH 03/14] net: sched: sch: add extack for init callback This patch adds extack support for init callback to prepare per-qdisc specific changes for extack. Cc: David Ahern Acked-by: Jamal Hadi Salim Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- include/net/sch_generic.h | 3 ++- net/sched/sch_api.c | 2 +- net/sched/sch_atm.c | 3 ++- net/sched/sch_cbq.c | 3 ++- net/sched/sch_cbs.c | 3 ++- net/sched/sch_choke.c | 3 ++- net/sched/sch_codel.c | 3 ++- net/sched/sch_drr.c | 3 ++- net/sched/sch_dsmark.c | 3 ++- net/sched/sch_fifo.c | 14 ++++++++++---- net/sched/sch_fq.c | 3 ++- net/sched/sch_fq_codel.c | 3 ++- net/sched/sch_generic.c | 8 +++++--- net/sched/sch_gred.c | 3 ++- net/sched/sch_hfsc.c | 3 ++- net/sched/sch_hhf.c | 3 ++- net/sched/sch_htb.c | 3 ++- net/sched/sch_ingress.c | 6 ++++-- net/sched/sch_mq.c | 3 ++- net/sched/sch_mqprio.c | 3 ++- net/sched/sch_multiq.c | 3 ++- net/sched/sch_netem.c | 3 ++- net/sched/sch_pie.c | 3 ++- net/sched/sch_plug.c | 3 ++- net/sched/sch_prio.c | 3 ++- net/sched/sch_qfq.c | 3 ++- net/sched/sch_red.c | 3 ++- net/sched/sch_sfb.c | 3 ++- net/sched/sch_sfq.c | 3 ++- net/sched/sch_tbf.c | 3 ++- net/sched/sch_teql.c | 3 ++- 31 files changed, 74 insertions(+), 37 deletions(-) diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index bc6b25faba99..4c5faa0ff47d 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -189,7 +189,8 @@ struct Qdisc_ops { struct sk_buff * (*dequeue)(struct Qdisc *); struct sk_buff * (*peek)(struct Qdisc *); - int (*init)(struct Qdisc *sch, struct nlattr *arg); + int (*init)(struct Qdisc *sch, struct nlattr *arg, + struct netlink_ext_ack *extack); void (*reset)(struct Qdisc *); void (*destroy)(struct Qdisc *); int (*change)(struct Qdisc *sch, diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 954c0fc45473..49ee016347d2 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1084,7 +1084,7 @@ static struct Qdisc *qdisc_create(struct net_device *dev, } if (ops->init) { - err = ops->init(sch, tca[TCA_OPTIONS]); + err = ops->init(sch, tca[TCA_OPTIONS], extack); if (err != 0) goto err_out5; } diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c index 2dbd249c0b2f..53a07687c0fb 100644 --- a/net/sched/sch_atm.c +++ b/net/sched/sch_atm.c @@ -531,7 +531,8 @@ static struct sk_buff *atm_tc_peek(struct Qdisc *sch) return p->link.q->ops->peek(p->link.q); } -static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt) +static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct atm_qdisc_data *p = qdisc_priv(sch); int err; diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index 0692fe35f4ec..86eba01457f3 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -1132,7 +1132,8 @@ static const struct nla_policy cbq_policy[TCA_CBQ_MAX + 1] = { [TCA_CBQ_POLICE] = { .len = sizeof(struct tc_cbq_police) }, }; -static int cbq_init(struct Qdisc *sch, struct nlattr *opt) +static int cbq_init(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct cbq_sched_data *q = qdisc_priv(sch); struct nlattr *tb[TCA_CBQ_MAX + 1]; diff --git a/net/sched/sch_cbs.c b/net/sched/sch_cbs.c index 7a72980c1509..d77c632a276c 100644 --- a/net/sched/sch_cbs.c +++ b/net/sched/sch_cbs.c @@ -291,7 +291,8 @@ static int cbs_change(struct Qdisc *sch, struct nlattr *opt) return 0; } -static int cbs_init(struct Qdisc *sch, struct nlattr *opt) +static int cbs_init(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct cbs_sched_data *q = qdisc_priv(sch); struct net_device *dev = qdisc_dev(sch); diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c index 531250fceb9e..49dda301e3bb 100644 --- a/net/sched/sch_choke.c +++ b/net/sched/sch_choke.c @@ -431,7 +431,8 @@ static int choke_change(struct Qdisc *sch, struct nlattr *opt) return 0; } -static int choke_init(struct Qdisc *sch, struct nlattr *opt) +static int choke_init(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { return choke_change(sch, opt); } diff --git a/net/sched/sch_codel.c b/net/sched/sch_codel.c index c518a1efcb9d..7221244e7f3b 100644 --- a/net/sched/sch_codel.c +++ b/net/sched/sch_codel.c @@ -184,7 +184,8 @@ static int codel_change(struct Qdisc *sch, struct nlattr *opt) return 0; } -static int codel_init(struct Qdisc *sch, struct nlattr *opt) +static int codel_init(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct codel_sched_data *q = qdisc_priv(sch); diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c index 5bbcef3dcd8c..1a88473cd768 100644 --- a/net/sched/sch_drr.c +++ b/net/sched/sch_drr.c @@ -408,7 +408,8 @@ out: return NULL; } -static int drr_init_qdisc(struct Qdisc *sch, struct nlattr *opt) +static int drr_init_qdisc(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct drr_sched *q = qdisc_priv(sch); int err; diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c index fb4fb71c68cf..16dd480b5583 100644 --- a/net/sched/sch_dsmark.c +++ b/net/sched/sch_dsmark.c @@ -330,7 +330,8 @@ static struct sk_buff *dsmark_peek(struct Qdisc *sch) return p->q->ops->peek(p->q); } -static int dsmark_init(struct Qdisc *sch, struct nlattr *opt) +static int dsmark_init(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct dsmark_qdisc_data *p = qdisc_priv(sch); struct nlattr *tb[TCA_DSMARK_MAX + 1]; diff --git a/net/sched/sch_fifo.c b/net/sched/sch_fifo.c index 1e37247656f8..a2d1c9f9b798 100644 --- a/net/sched/sch_fifo.c +++ b/net/sched/sch_fifo.c @@ -55,7 +55,8 @@ static int pfifo_tail_enqueue(struct sk_buff *skb, struct Qdisc *sch, return NET_XMIT_CN; } -static int fifo_init(struct Qdisc *sch, struct nlattr *opt) +static int fifo_init(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { bool bypass; bool is_bfifo = sch->ops == &bfifo_qdisc_ops; @@ -88,6 +89,11 @@ static int fifo_init(struct Qdisc *sch, struct nlattr *opt) return 0; } +static int fifo_change(struct Qdisc *sch, struct nlattr *opt) +{ + return fifo_init(sch, opt, NULL); +} + static int fifo_dump(struct Qdisc *sch, struct sk_buff *skb) { struct tc_fifo_qopt opt = { .limit = sch->limit }; @@ -108,7 +114,7 @@ struct Qdisc_ops pfifo_qdisc_ops __read_mostly = { .peek = qdisc_peek_head, .init = fifo_init, .reset = qdisc_reset_queue, - .change = fifo_init, + .change = fifo_change, .dump = fifo_dump, .owner = THIS_MODULE, }; @@ -122,7 +128,7 @@ struct Qdisc_ops bfifo_qdisc_ops __read_mostly = { .peek = qdisc_peek_head, .init = fifo_init, .reset = qdisc_reset_queue, - .change = fifo_init, + .change = fifo_change, .dump = fifo_dump, .owner = THIS_MODULE, }; @@ -136,7 +142,7 @@ struct Qdisc_ops pfifo_head_drop_qdisc_ops __read_mostly = { .peek = qdisc_peek_head, .init = fifo_init, .reset = qdisc_reset_queue, - .change = fifo_init, + .change = fifo_change, .dump = fifo_dump, .owner = THIS_MODULE, }; diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c index 263d16e3219e..c9f61ffe220e 100644 --- a/net/sched/sch_fq.c +++ b/net/sched/sch_fq.c @@ -788,7 +788,8 @@ static void fq_destroy(struct Qdisc *sch) qdisc_watchdog_cancel(&q->watchdog); } -static int fq_init(struct Qdisc *sch, struct nlattr *opt) +static int fq_init(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct fq_sched_data *q = qdisc_priv(sch); int err; diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c index 0305d791ea94..5d0b20898ffa 100644 --- a/net/sched/sch_fq_codel.c +++ b/net/sched/sch_fq_codel.c @@ -458,7 +458,8 @@ static void fq_codel_destroy(struct Qdisc *sch) kvfree(q->flows); } -static int fq_codel_init(struct Qdisc *sch, struct nlattr *opt) +static int fq_codel_init(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct fq_codel_sched_data *q = qdisc_priv(sch); int i; diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 876fab2604b8..30bc38c5d7ae 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -551,7 +551,8 @@ struct Qdisc noop_qdisc = { }; EXPORT_SYMBOL(noop_qdisc); -static int noqueue_init(struct Qdisc *qdisc, struct nlattr *opt) +static int noqueue_init(struct Qdisc *qdisc, struct nlattr *opt, + struct netlink_ext_ack *extack) { /* register_qdisc() assigns a default of noop_enqueue if unset, * but __dev_queue_xmit() treats noqueue only as such @@ -690,7 +691,8 @@ nla_put_failure: return -1; } -static int pfifo_fast_init(struct Qdisc *qdisc, struct nlattr *opt) +static int pfifo_fast_init(struct Qdisc *qdisc, struct nlattr *opt, + struct netlink_ext_ack *extack) { unsigned int qlen = qdisc_dev(qdisc)->tx_queue_len; struct pfifo_fast_priv *priv = qdisc_priv(qdisc); @@ -840,7 +842,7 @@ struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue, } sch->parent = parentid; - if (!ops->init || ops->init(sch, NULL) == 0) + if (!ops->init || ops->init(sch, NULL, NULL) == 0) return sch; qdisc_destroy(sch); diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c index ccd1a00e2a9a..4cab6ccad643 100644 --- a/net/sched/sch_gred.c +++ b/net/sched/sch_gred.c @@ -466,7 +466,8 @@ errout: return err; } -static int gred_init(struct Qdisc *sch, struct nlattr *opt) +static int gred_init(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct nlattr *tb[TCA_GRED_MAX + 1]; int err; diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index 94db20352f37..1102943c46c9 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -1388,7 +1388,8 @@ hfsc_schedule_watchdog(struct Qdisc *sch) } static int -hfsc_init_qdisc(struct Qdisc *sch, struct nlattr *opt) +hfsc_init_qdisc(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct hfsc_sched *q = qdisc_priv(sch); struct tc_hfsc_qopt *qopt; diff --git a/net/sched/sch_hhf.c b/net/sched/sch_hhf.c index 73a53c08091b..b3a80f0ed4b0 100644 --- a/net/sched/sch_hhf.c +++ b/net/sched/sch_hhf.c @@ -571,7 +571,8 @@ static int hhf_change(struct Qdisc *sch, struct nlattr *opt) return 0; } -static int hhf_init(struct Qdisc *sch, struct nlattr *opt) +static int hhf_init(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct hhf_sched_data *q = qdisc_priv(sch); int i; diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index fa0380730ff0..41d9b7da9273 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -1017,7 +1017,8 @@ static void htb_work_func(struct work_struct *work) rcu_read_unlock(); } -static int htb_init(struct Qdisc *sch, struct nlattr *opt) +static int htb_init(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct htb_sched *q = qdisc_priv(sch); struct nlattr *tb[TCA_HTB_MAX + 1]; diff --git a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c index fc1286f499c1..a6f175e64016 100644 --- a/net/sched/sch_ingress.c +++ b/net/sched/sch_ingress.c @@ -62,7 +62,8 @@ static void clsact_chain_head_change(struct tcf_proto *tp_head, void *priv) mini_qdisc_pair_swap(miniqp, tp_head); } -static int ingress_init(struct Qdisc *sch, struct nlattr *opt) +static int ingress_init(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct ingress_sched_data *q = qdisc_priv(sch); struct net_device *dev = qdisc_dev(sch); @@ -167,7 +168,8 @@ static struct tcf_block *clsact_tcf_block(struct Qdisc *sch, unsigned long cl) } } -static int clsact_init(struct Qdisc *sch, struct nlattr *opt) +static int clsact_init(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct clsact_sched_data *q = qdisc_priv(sch); struct net_device *dev = qdisc_dev(sch); diff --git a/net/sched/sch_mq.c b/net/sched/sch_mq.c index 8cbb5c829d59..b91f7d8cb184 100644 --- a/net/sched/sch_mq.c +++ b/net/sched/sch_mq.c @@ -36,7 +36,8 @@ static void mq_destroy(struct Qdisc *sch) kfree(priv->qdiscs); } -static int mq_init(struct Qdisc *sch, struct nlattr *opt) +static int mq_init(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct net_device *dev = qdisc_dev(sch); struct mq_sched *priv = qdisc_priv(sch); diff --git a/net/sched/sch_mqprio.c b/net/sched/sch_mqprio.c index 8622745f3cd9..0379fc4ee7bb 100644 --- a/net/sched/sch_mqprio.c +++ b/net/sched/sch_mqprio.c @@ -132,7 +132,8 @@ static int parse_attr(struct nlattr *tb[], int maxtype, struct nlattr *nla, return 0; } -static int mqprio_init(struct Qdisc *sch, struct nlattr *opt) +static int mqprio_init(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct net_device *dev = qdisc_dev(sch); struct mqprio_sched *priv = qdisc_priv(sch); diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c index 37195e0c64ba..54132dde6d42 100644 --- a/net/sched/sch_multiq.c +++ b/net/sched/sch_multiq.c @@ -236,7 +236,8 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt) return 0; } -static int multiq_init(struct Qdisc *sch, struct nlattr *opt) +static int multiq_init(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct multiq_sched_data *q = qdisc_priv(sch); int i, err; diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index dd70924cbcdf..6490ce08d29e 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -984,7 +984,8 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt) return ret; } -static int netem_init(struct Qdisc *sch, struct nlattr *opt) +static int netem_init(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct netem_sched_data *q = qdisc_priv(sch); int ret; diff --git a/net/sched/sch_pie.c b/net/sched/sch_pie.c index 776c694c77c7..c4c87ed3971f 100644 --- a/net/sched/sch_pie.c +++ b/net/sched/sch_pie.c @@ -439,7 +439,8 @@ static void pie_timer(struct timer_list *t) } -static int pie_init(struct Qdisc *sch, struct nlattr *opt) +static int pie_init(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct pie_sched_data *q = qdisc_priv(sch); diff --git a/net/sched/sch_plug.c b/net/sched/sch_plug.c index 1c6cbab3e7b9..d9c6fbe55ae5 100644 --- a/net/sched/sch_plug.c +++ b/net/sched/sch_plug.c @@ -123,7 +123,8 @@ static struct sk_buff *plug_dequeue(struct Qdisc *sch) return qdisc_dequeue_head(sch); } -static int plug_init(struct Qdisc *sch, struct nlattr *opt) +static int plug_init(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct plug_sched_data *q = qdisc_priv(sch); diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index 2c79559a0d31..8632d795e6ee 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -205,7 +205,8 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt) return 0; } -static int prio_init(struct Qdisc *sch, struct nlattr *opt) +static int prio_init(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct prio_sched_data *q = qdisc_priv(sch); int err; diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index 6962b37a3ad3..7c1b976314bd 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c @@ -1413,7 +1413,8 @@ static void qfq_qlen_notify(struct Qdisc *sch, unsigned long arg) qfq_deactivate_class(q, cl); } -static int qfq_init_qdisc(struct Qdisc *sch, struct nlattr *opt) +static int qfq_init_qdisc(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct qfq_sched *q = qdisc_priv(sch); struct qfq_group *grp; diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c index f0747eb87dc4..46d12206c7af 100644 --- a/net/sched/sch_red.c +++ b/net/sched/sch_red.c @@ -272,7 +272,8 @@ static inline void red_adaptative_timer(struct timer_list *t) spin_unlock(root_lock); } -static int red_init(struct Qdisc *sch, struct nlattr *opt) +static int red_init(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct red_sched_data *q = qdisc_priv(sch); diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c index 0678debdd856..b2205eaa0f51 100644 --- a/net/sched/sch_sfb.c +++ b/net/sched/sch_sfb.c @@ -549,7 +549,8 @@ static int sfb_change(struct Qdisc *sch, struct nlattr *opt) return 0; } -static int sfb_init(struct Qdisc *sch, struct nlattr *opt) +static int sfb_init(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct sfb_sched_data *q = qdisc_priv(sch); int err; diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c index 930e5bd26d3d..3b5869c7b3f3 100644 --- a/net/sched/sch_sfq.c +++ b/net/sched/sch_sfq.c @@ -721,7 +721,8 @@ static void sfq_destroy(struct Qdisc *sch) kfree(q->red_parms); } -static int sfq_init(struct Qdisc *sch, struct nlattr *opt) +static int sfq_init(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct sfq_sched_data *q = qdisc_priv(sch); int i; diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index e8f3345674c5..9abff1271ec0 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c @@ -421,7 +421,8 @@ done: return err; } -static int tbf_init(struct Qdisc *sch, struct nlattr *opt) +static int tbf_init(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct tbf_sched_data *q = qdisc_priv(sch); diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index 9fe6b427afed..93f04cf5cac1 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c @@ -167,7 +167,8 @@ teql_destroy(struct Qdisc *sch) } } -static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt) +static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct net_device *dev = qdisc_dev(sch); struct teql_master *m = (struct teql_master *)sch->ops; From 2030721cc0c39ff19df94a0df77b0401fdb71c1a Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 20 Dec 2017 12:35:14 -0500 Subject: [PATCH 04/14] net: sched: sch: add extack for change qdisc ops This patch adds extack support for change callback for qdisc ops structtur to prepare per-qdisc specific changes for extack. Cc: David Ahern Acked-by: Jamal Hadi Salim Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- include/net/sch_generic.h | 3 ++- net/sched/sch_api.c | 2 +- net/sched/sch_cbs.c | 5 +++-- net/sched/sch_choke.c | 5 +++-- net/sched/sch_codel.c | 5 +++-- net/sched/sch_fifo.c | 13 ++++--------- net/sched/sch_fq.c | 5 +++-- net/sched/sch_fq_codel.c | 5 +++-- net/sched/sch_gred.c | 3 ++- net/sched/sch_hfsc.c | 3 ++- net/sched/sch_hhf.c | 5 +++-- net/sched/sch_multiq.c | 5 +++-- net/sched/sch_netem.c | 5 +++-- net/sched/sch_pie.c | 5 +++-- net/sched/sch_plug.c | 3 ++- net/sched/sch_prio.c | 5 +++-- net/sched/sch_red.c | 5 +++-- net/sched/sch_sfb.c | 5 +++-- net/sched/sch_tbf.c | 5 +++-- 19 files changed, 52 insertions(+), 40 deletions(-) diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index 4c5faa0ff47d..e7a3e206b904 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -194,7 +194,8 @@ struct Qdisc_ops { void (*reset)(struct Qdisc *); void (*destroy)(struct Qdisc *); int (*change)(struct Qdisc *sch, - struct nlattr *arg); + struct nlattr *arg, + struct netlink_ext_ack *extack); void (*attach)(struct Qdisc *sch); int (*dump)(struct Qdisc *, struct sk_buff *); diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 49ee016347d2..fcc70415fd26 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1177,7 +1177,7 @@ static int qdisc_change(struct Qdisc *sch, struct nlattr **tca, NL_SET_ERR_MSG(extack, "Change operation not supported by specified qdisc"); return -EINVAL; } - err = sch->ops->change(sch, tca[TCA_OPTIONS]); + err = sch->ops->change(sch, tca[TCA_OPTIONS], extack); if (err) return err; } diff --git a/net/sched/sch_cbs.c b/net/sched/sch_cbs.c index d77c632a276c..8bf6e163d29c 100644 --- a/net/sched/sch_cbs.c +++ b/net/sched/sch_cbs.c @@ -246,7 +246,8 @@ static int cbs_enable_offload(struct net_device *dev, struct cbs_sched_data *q, return 0; } -static int cbs_change(struct Qdisc *sch, struct nlattr *opt) +static int cbs_change(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct cbs_sched_data *q = qdisc_priv(sch); struct net_device *dev = qdisc_dev(sch); @@ -307,7 +308,7 @@ static int cbs_init(struct Qdisc *sch, struct nlattr *opt, qdisc_watchdog_init(&q->watchdog, sch); - return cbs_change(sch, opt); + return cbs_change(sch, opt, extack); } static void cbs_destroy(struct Qdisc *sch) diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c index 49dda301e3bb..eafc0d17d174 100644 --- a/net/sched/sch_choke.c +++ b/net/sched/sch_choke.c @@ -344,7 +344,8 @@ static void choke_free(void *addr) kvfree(addr); } -static int choke_change(struct Qdisc *sch, struct nlattr *opt) +static int choke_change(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct choke_sched_data *q = qdisc_priv(sch); struct nlattr *tb[TCA_CHOKE_MAX + 1]; @@ -434,7 +435,7 @@ static int choke_change(struct Qdisc *sch, struct nlattr *opt) static int choke_init(struct Qdisc *sch, struct nlattr *opt, struct netlink_ext_ack *extack) { - return choke_change(sch, opt); + return choke_change(sch, opt, extack); } static int choke_dump(struct Qdisc *sch, struct sk_buff *skb) diff --git a/net/sched/sch_codel.c b/net/sched/sch_codel.c index 7221244e7f3b..17cd81f84b5d 100644 --- a/net/sched/sch_codel.c +++ b/net/sched/sch_codel.c @@ -130,7 +130,8 @@ static const struct nla_policy codel_policy[TCA_CODEL_MAX + 1] = { [TCA_CODEL_CE_THRESHOLD]= { .type = NLA_U32 }, }; -static int codel_change(struct Qdisc *sch, struct nlattr *opt) +static int codel_change(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct codel_sched_data *q = qdisc_priv(sch); struct nlattr *tb[TCA_CODEL_MAX + 1]; @@ -197,7 +198,7 @@ static int codel_init(struct Qdisc *sch, struct nlattr *opt, q->params.mtu = psched_mtu(qdisc_dev(sch)); if (opt) { - int err = codel_change(sch, opt); + int err = codel_change(sch, opt, extack); if (err) return err; diff --git a/net/sched/sch_fifo.c b/net/sched/sch_fifo.c index a2d1c9f9b798..c65f23c70f40 100644 --- a/net/sched/sch_fifo.c +++ b/net/sched/sch_fifo.c @@ -89,11 +89,6 @@ static int fifo_init(struct Qdisc *sch, struct nlattr *opt, return 0; } -static int fifo_change(struct Qdisc *sch, struct nlattr *opt) -{ - return fifo_init(sch, opt, NULL); -} - static int fifo_dump(struct Qdisc *sch, struct sk_buff *skb) { struct tc_fifo_qopt opt = { .limit = sch->limit }; @@ -114,7 +109,7 @@ struct Qdisc_ops pfifo_qdisc_ops __read_mostly = { .peek = qdisc_peek_head, .init = fifo_init, .reset = qdisc_reset_queue, - .change = fifo_change, + .change = fifo_init, .dump = fifo_dump, .owner = THIS_MODULE, }; @@ -128,7 +123,7 @@ struct Qdisc_ops bfifo_qdisc_ops __read_mostly = { .peek = qdisc_peek_head, .init = fifo_init, .reset = qdisc_reset_queue, - .change = fifo_change, + .change = fifo_init, .dump = fifo_dump, .owner = THIS_MODULE, }; @@ -142,7 +137,7 @@ struct Qdisc_ops pfifo_head_drop_qdisc_ops __read_mostly = { .peek = qdisc_peek_head, .init = fifo_init, .reset = qdisc_reset_queue, - .change = fifo_change, + .change = fifo_init, .dump = fifo_dump, .owner = THIS_MODULE, }; @@ -163,7 +158,7 @@ int fifo_set_limit(struct Qdisc *q, unsigned int limit) nla->nla_len = nla_attr_size(sizeof(struct tc_fifo_qopt)); ((struct tc_fifo_qopt *)nla_data(nla))->limit = limit; - ret = q->ops->change(q, nla); + ret = q->ops->change(q, nla, NULL); kfree(nla); } return ret; diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c index c9f61ffe220e..a366e4c9413a 100644 --- a/net/sched/sch_fq.c +++ b/net/sched/sch_fq.c @@ -685,7 +685,8 @@ static const struct nla_policy fq_policy[TCA_FQ_MAX + 1] = { [TCA_FQ_LOW_RATE_THRESHOLD] = { .type = NLA_U32 }, }; -static int fq_change(struct Qdisc *sch, struct nlattr *opt) +static int fq_change(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct fq_sched_data *q = qdisc_priv(sch); struct nlattr *tb[TCA_FQ_MAX + 1]; @@ -812,7 +813,7 @@ static int fq_init(struct Qdisc *sch, struct nlattr *opt, qdisc_watchdog_init(&q->watchdog, sch); if (opt) - err = fq_change(sch, opt); + err = fq_change(sch, opt, extack); else err = fq_resize(sch, q->fq_trees_log); diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c index 5d0b20898ffa..d798c93f7c96 100644 --- a/net/sched/sch_fq_codel.c +++ b/net/sched/sch_fq_codel.c @@ -377,7 +377,8 @@ static const struct nla_policy fq_codel_policy[TCA_FQ_CODEL_MAX + 1] = { [TCA_FQ_CODEL_MEMORY_LIMIT] = { .type = NLA_U32 }, }; -static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt) +static int fq_codel_change(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct fq_codel_sched_data *q = qdisc_priv(sch); struct nlattr *tb[TCA_FQ_CODEL_MAX + 1]; @@ -478,7 +479,7 @@ static int fq_codel_init(struct Qdisc *sch, struct nlattr *opt, q->cparams.mtu = psched_mtu(qdisc_dev(sch)); if (opt) { - int err = fq_codel_change(sch, opt); + int err = fq_codel_change(sch, opt, NULL); if (err) return err; } diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c index 4cab6ccad643..cbe4831f46f4 100644 --- a/net/sched/sch_gred.c +++ b/net/sched/sch_gred.c @@ -392,7 +392,8 @@ static const struct nla_policy gred_policy[TCA_GRED_MAX + 1] = { [TCA_GRED_LIMIT] = { .type = NLA_U32 }, }; -static int gred_change(struct Qdisc *sch, struct nlattr *opt) +static int gred_change(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct gred_sched *table = qdisc_priv(sch); struct tc_gred_qopt *ctl; diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index 1102943c46c9..f49a4a4fe095 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -1430,7 +1430,8 @@ hfsc_init_qdisc(struct Qdisc *sch, struct nlattr *opt, } static int -hfsc_change_qdisc(struct Qdisc *sch, struct nlattr *opt) +hfsc_change_qdisc(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct hfsc_sched *q = qdisc_priv(sch); struct tc_hfsc_qopt *qopt; diff --git a/net/sched/sch_hhf.c b/net/sched/sch_hhf.c index b3a80f0ed4b0..bce2632212d3 100644 --- a/net/sched/sch_hhf.c +++ b/net/sched/sch_hhf.c @@ -504,7 +504,8 @@ static const struct nla_policy hhf_policy[TCA_HHF_MAX + 1] = { [TCA_HHF_NON_HH_WEIGHT] = { .type = NLA_U32 }, }; -static int hhf_change(struct Qdisc *sch, struct nlattr *opt) +static int hhf_change(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct hhf_sched_data *q = qdisc_priv(sch); struct nlattr *tb[TCA_HHF_MAX + 1]; @@ -590,7 +591,7 @@ static int hhf_init(struct Qdisc *sch, struct nlattr *opt, q->hhf_non_hh_weight = 2; if (opt) { - int err = hhf_change(sch, opt); + int err = hhf_change(sch, opt, extack); if (err) return err; diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c index 54132dde6d42..a8db1dbeb04f 100644 --- a/net/sched/sch_multiq.c +++ b/net/sched/sch_multiq.c @@ -180,7 +180,8 @@ multiq_destroy(struct Qdisc *sch) kfree(q->queues); } -static int multiq_tune(struct Qdisc *sch, struct nlattr *opt) +static int multiq_tune(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct multiq_sched_data *q = qdisc_priv(sch); struct tc_multiq_qopt *qopt; @@ -259,7 +260,7 @@ static int multiq_init(struct Qdisc *sch, struct nlattr *opt, for (i = 0; i < q->max_bands; i++) q->queues[i] = &noop_qdisc; - return multiq_tune(sch, opt); + return multiq_tune(sch, opt, extack); } static int multiq_dump(struct Qdisc *sch, struct sk_buff *skb) diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index 6490ce08d29e..f45040b55531 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -893,7 +893,8 @@ static int parse_attr(struct nlattr *tb[], int maxtype, struct nlattr *nla, } /* Parse netlink message to set options */ -static int netem_change(struct Qdisc *sch, struct nlattr *opt) +static int netem_change(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct netem_sched_data *q = qdisc_priv(sch); struct nlattr *tb[TCA_NETEM_MAX + 1]; @@ -996,7 +997,7 @@ static int netem_init(struct Qdisc *sch, struct nlattr *opt, return -EINVAL; q->loss_model = CLG_RANDOM; - ret = netem_change(sch, opt); + ret = netem_change(sch, opt, extack); if (ret) pr_info("netem: change failed\n"); return ret; diff --git a/net/sched/sch_pie.c b/net/sched/sch_pie.c index c4c87ed3971f..18d30bb86881 100644 --- a/net/sched/sch_pie.c +++ b/net/sched/sch_pie.c @@ -181,7 +181,8 @@ static const struct nla_policy pie_policy[TCA_PIE_MAX + 1] = { [TCA_PIE_BYTEMODE] = {.type = NLA_U32}, }; -static int pie_change(struct Qdisc *sch, struct nlattr *opt) +static int pie_change(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct pie_sched_data *q = qdisc_priv(sch); struct nlattr *tb[TCA_PIE_MAX + 1]; @@ -452,7 +453,7 @@ static int pie_init(struct Qdisc *sch, struct nlattr *opt, timer_setup(&q->adapt_timer, pie_timer, 0); if (opt) { - int err = pie_change(sch, opt); + int err = pie_change(sch, opt, extack); if (err) return err; diff --git a/net/sched/sch_plug.c b/net/sched/sch_plug.c index d9c6fbe55ae5..5619d2eb17b6 100644 --- a/net/sched/sch_plug.c +++ b/net/sched/sch_plug.c @@ -159,7 +159,8 @@ static int plug_init(struct Qdisc *sch, struct nlattr *opt, * command is received (just act as a pass-thru queue). * TCQ_PLUG_LIMIT: Increase/decrease queue size */ -static int plug_change(struct Qdisc *sch, struct nlattr *opt) +static int plug_change(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct plug_sched_data *q = qdisc_priv(sch); struct tc_plug_qopt *msg; diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index 8632d795e6ee..5f8ecbaa2610 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -153,7 +153,8 @@ prio_destroy(struct Qdisc *sch) qdisc_destroy(q->queues[prio]); } -static int prio_tune(struct Qdisc *sch, struct nlattr *opt) +static int prio_tune(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct prio_sched_data *q = qdisc_priv(sch); struct Qdisc *queues[TCQ_PRIO_BANDS]; @@ -218,7 +219,7 @@ static int prio_init(struct Qdisc *sch, struct nlattr *opt, if (err) return err; - return prio_tune(sch, opt); + return prio_tune(sch, opt, extack); } static int prio_dump(struct Qdisc *sch, struct sk_buff *skb) diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c index 46d12206c7af..6b85f8334b74 100644 --- a/net/sched/sch_red.c +++ b/net/sched/sch_red.c @@ -197,7 +197,8 @@ static const struct nla_policy red_policy[TCA_RED_MAX + 1] = { [TCA_RED_MAX_P] = { .type = NLA_U32 }, }; -static int red_change(struct Qdisc *sch, struct nlattr *opt) +static int red_change(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct red_sched_data *q = qdisc_priv(sch); struct nlattr *tb[TCA_RED_MAX + 1]; @@ -280,7 +281,7 @@ static int red_init(struct Qdisc *sch, struct nlattr *opt, q->qdisc = &noop_qdisc; q->sch = sch; timer_setup(&q->adapt_timer, red_adaptative_timer, 0); - return red_change(sch, opt); + return red_change(sch, opt, extack); } static int red_dump_offload_stats(struct Qdisc *sch, struct tc_red_qopt *opt) diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c index b2205eaa0f51..1b9d69bd6ed6 100644 --- a/net/sched/sch_sfb.c +++ b/net/sched/sch_sfb.c @@ -488,7 +488,8 @@ static const struct tc_sfb_qopt sfb_default_ops = { .penalty_burst = 20, }; -static int sfb_change(struct Qdisc *sch, struct nlattr *opt) +static int sfb_change(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { struct sfb_sched_data *q = qdisc_priv(sch); struct Qdisc *child; @@ -560,7 +561,7 @@ static int sfb_init(struct Qdisc *sch, struct nlattr *opt, return err; q->qdisc = &noop_qdisc; - return sfb_change(sch, opt); + return sfb_change(sch, opt, extack); } static int sfb_dump(struct Qdisc *sch, struct sk_buff *skb) diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index 9abff1271ec0..273228eb5ce0 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c @@ -302,7 +302,8 @@ static const struct nla_policy tbf_policy[TCA_TBF_MAX + 1] = { [TCA_TBF_PBURST] = { .type = NLA_U32 }, }; -static int tbf_change(struct Qdisc *sch, struct nlattr *opt) +static int tbf_change(struct Qdisc *sch, struct nlattr *opt, + struct netlink_ext_ack *extack) { int err; struct tbf_sched_data *q = qdisc_priv(sch); @@ -434,7 +435,7 @@ static int tbf_init(struct Qdisc *sch, struct nlattr *opt, q->t_c = ktime_get_ns(); - return tbf_change(sch, opt); + return tbf_change(sch, opt, extack); } static void tbf_destroy(struct Qdisc *sch) From 793d81d6a1965f1e1806ebc9aacc84a639b90282 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 20 Dec 2017 12:35:15 -0500 Subject: [PATCH 05/14] net: sched: sch: add extack to change class This patch adds extack support for class change callback api. This prepares to handle extack support inside each specific class implementation. Cc: David Ahern Acked-by: Jamal Hadi Salim Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- include/net/sch_generic.h | 3 ++- net/sched/sch_api.c | 2 +- net/sched/sch_atm.c | 3 ++- net/sched/sch_cbq.c | 2 +- net/sched/sch_drr.c | 3 ++- net/sched/sch_dsmark.c | 3 ++- net/sched/sch_fq_codel.c | 2 +- net/sched/sch_hfsc.c | 3 ++- net/sched/sch_htb.c | 2 +- net/sched/sch_qfq.c | 3 ++- net/sched/sch_sfb.c | 3 ++- 11 files changed, 18 insertions(+), 11 deletions(-) diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index e7a3e206b904..b4660a3ea99c 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -158,7 +158,8 @@ struct Qdisc_class_ops { /* Class manipulation routines */ unsigned long (*find)(struct Qdisc *, u32 classid); int (*change)(struct Qdisc *, u32, u32, - struct nlattr **, unsigned long *); + struct nlattr **, unsigned long *, + struct netlink_ext_ack *); int (*delete)(struct Qdisc *, unsigned long); void (*walk)(struct Qdisc *, struct qdisc_walker * arg); diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index fcc70415fd26..6cf2f7dadbdb 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1907,7 +1907,7 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, new_cl = cl; err = -EOPNOTSUPP; if (cops->change) - err = cops->change(q, clid, portid, tca, &new_cl); + err = cops->change(q, clid, portid, tca, &new_cl, extack); if (err == 0) { tclass_notify(net, skb, n, q, new_cl, RTM_NEWTCLASS); /* We just create a new class, need to do reverse binding. */ diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c index 53a07687c0fb..80ada9affe81 100644 --- a/net/sched/sch_atm.c +++ b/net/sched/sch_atm.c @@ -191,7 +191,8 @@ static const struct nla_policy atm_policy[TCA_ATM_MAX + 1] = { }; static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent, - struct nlattr **tca, unsigned long *arg) + struct nlattr **tca, unsigned long *arg, + struct netlink_ext_ack *extack) { struct atm_qdisc_data *p = qdisc_priv(sch); struct atm_flow_data *flow = (struct atm_flow_data *)*arg; diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index 86eba01457f3..8f1832df8b4f 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -1452,7 +1452,7 @@ static void cbq_destroy(struct Qdisc *sch) static int cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **tca, - unsigned long *arg) + unsigned long *arg, struct netlink_ext_ack *extack) { int err; struct cbq_sched_data *q = qdisc_priv(sch); diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c index 1a88473cd768..73b914bc47a4 100644 --- a/net/sched/sch_drr.c +++ b/net/sched/sch_drr.c @@ -64,7 +64,8 @@ static const struct nla_policy drr_policy[TCA_DRR_MAX + 1] = { }; static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid, - struct nlattr **tca, unsigned long *arg) + struct nlattr **tca, unsigned long *arg, + struct netlink_ext_ack *extack) { struct drr_sched *q = qdisc_priv(sch); struct drr_class *cl = (struct drr_class *)*arg; diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c index 16dd480b5583..89e433bbd590 100644 --- a/net/sched/sch_dsmark.c +++ b/net/sched/sch_dsmark.c @@ -112,7 +112,8 @@ static const struct nla_policy dsmark_policy[TCA_DSMARK_MAX + 1] = { }; static int dsmark_change(struct Qdisc *sch, u32 classid, u32 parent, - struct nlattr **tca, unsigned long *arg) + struct nlattr **tca, unsigned long *arg, + struct netlink_ext_ack *extack) { struct dsmark_qdisc_data *p = qdisc_priv(sch); struct nlattr *opt = tca[TCA_OPTIONS]; diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c index d798c93f7c96..b4ca46aafb5a 100644 --- a/net/sched/sch_fq_codel.c +++ b/net/sched/sch_fq_codel.c @@ -479,7 +479,7 @@ static int fq_codel_init(struct Qdisc *sch, struct nlattr *opt, q->cparams.mtu = psched_mtu(qdisc_dev(sch)); if (opt) { - int err = fq_codel_change(sch, opt, NULL); + int err = fq_codel_change(sch, opt, extack); if (err) return err; } diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index f49a4a4fe095..11410b0e4068 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -921,7 +921,8 @@ static const struct nla_policy hfsc_policy[TCA_HFSC_MAX + 1] = { static int hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, - struct nlattr **tca, unsigned long *arg) + struct nlattr **tca, unsigned long *arg, + struct netlink_ext_ack *extack) { struct hfsc_sched *q = qdisc_priv(sch); struct hfsc_class *cl = (struct hfsc_class *)*arg; diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 41d9b7da9273..eb535a23a69b 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -1327,7 +1327,7 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg) static int htb_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **tca, - unsigned long *arg) + unsigned long *arg, struct netlink_ext_ack *extack) { int err = -EINVAL; struct htb_sched *q = qdisc_priv(sch); diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index 7c1b976314bd..1f4a84b687d2 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c @@ -402,7 +402,8 @@ static int qfq_change_agg(struct Qdisc *sch, struct qfq_class *cl, u32 weight, } static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, - struct nlattr **tca, unsigned long *arg) + struct nlattr **tca, unsigned long *arg, + struct netlink_ext_ack *extack) { struct qfq_sched *q = qdisc_priv(sch); struct qfq_class *cl = (struct qfq_class *)*arg; diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c index 1b9d69bd6ed6..d70d470361be 100644 --- a/net/sched/sch_sfb.c +++ b/net/sched/sch_sfb.c @@ -645,7 +645,8 @@ static void sfb_unbind(struct Qdisc *sch, unsigned long arg) } static int sfb_change_class(struct Qdisc *sch, u32 classid, u32 parentid, - struct nlattr **tca, unsigned long *arg) + struct nlattr **tca, unsigned long *arg, + struct netlink_ext_ack *extack) { return -ENOSYS; } From cbaacc4e8a394d63bcd707775ca5bb7a51aaabee Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 20 Dec 2017 12:35:16 -0500 Subject: [PATCH 06/14] net: sched: sch: add extack for block callback This patch adds extack support for block callback to prepare per-qdisc specific changes for extack. Cc: David Ahern Acked-by: Jamal Hadi Salim Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- include/net/sch_generic.h | 3 ++- net/sched/cls_api.c | 4 ++-- net/sched/sch_api.c | 2 +- net/sched/sch_atm.c | 3 ++- net/sched/sch_cbq.c | 3 ++- net/sched/sch_drr.c | 3 ++- net/sched/sch_dsmark.c | 3 ++- net/sched/sch_fq_codel.c | 3 ++- net/sched/sch_hfsc.c | 3 ++- net/sched/sch_htb.c | 3 ++- net/sched/sch_ingress.c | 6 ++++-- net/sched/sch_multiq.c | 3 ++- net/sched/sch_prio.c | 3 ++- net/sched/sch_qfq.c | 3 ++- net/sched/sch_sfb.c | 3 ++- net/sched/sch_sfq.c | 3 ++- 16 files changed, 33 insertions(+), 18 deletions(-) diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index b4660a3ea99c..f65dd2837142 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -165,7 +165,8 @@ struct Qdisc_class_ops { /* Filter manipulation */ struct tcf_block * (*tcf_block)(struct Qdisc *sch, - unsigned long arg); + unsigned long arg, + struct netlink_ext_ack *extack); unsigned long (*bind_tcf)(struct Qdisc *, unsigned long, u32 classid); void (*unbind_tcf)(struct Qdisc *, unsigned long); diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 32b1ea7cf863..22b977d40e1d 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -793,7 +793,7 @@ replay: } /* And the last stroke */ - block = cops->tcf_block(q, cl); + block = cops->tcf_block(q, cl, extack); if (!block) { err = -EINVAL; goto errout; @@ -1040,7 +1040,7 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb) if (cl == 0) goto out; } - block = cops->tcf_block(q, cl); + block = cops->tcf_block(q, cl, NULL); if (!block) goto out; diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 6cf2f7dadbdb..8c8c15b4da3b 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1760,7 +1760,7 @@ static void tc_bind_tclass(struct Qdisc *q, u32 portid, u32 clid, cl = cops->find(q, portid); if (!cl) return; - block = cops->tcf_block(q, cl); + block = cops->tcf_block(q, cl, NULL); if (!block) return; list_for_each_entry(chain, &block->chain_list, list) { diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c index 80ada9affe81..b606a75af333 100644 --- a/net/sched/sch_atm.c +++ b/net/sched/sch_atm.c @@ -357,7 +357,8 @@ static void atm_tc_walk(struct Qdisc *sch, struct qdisc_walker *walker) } } -static struct tcf_block *atm_tc_tcf_block(struct Qdisc *sch, unsigned long cl) +static struct tcf_block *atm_tc_tcf_block(struct Qdisc *sch, unsigned long cl, + struct netlink_ext_ack *extack) { struct atm_qdisc_data *p = qdisc_priv(sch); struct atm_flow_data *flow = (struct atm_flow_data *)cl; diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index 8f1832df8b4f..d46048a439a6 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -1679,7 +1679,8 @@ static int cbq_delete(struct Qdisc *sch, unsigned long arg) return 0; } -static struct tcf_block *cbq_tcf_block(struct Qdisc *sch, unsigned long arg) +static struct tcf_block *cbq_tcf_block(struct Qdisc *sch, unsigned long arg, + struct netlink_ext_ack *extack) { struct cbq_sched_data *q = qdisc_priv(sch); struct cbq_class *cl = (struct cbq_class *)arg; diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c index 73b914bc47a4..44a2870f6f10 100644 --- a/net/sched/sch_drr.c +++ b/net/sched/sch_drr.c @@ -173,7 +173,8 @@ static unsigned long drr_search_class(struct Qdisc *sch, u32 classid) return (unsigned long)drr_find_class(sch, classid); } -static struct tcf_block *drr_tcf_block(struct Qdisc *sch, unsigned long cl) +static struct tcf_block *drr_tcf_block(struct Qdisc *sch, unsigned long cl, + struct netlink_ext_ack *extack) { struct drr_sched *q = qdisc_priv(sch); diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c index 89e433bbd590..5dc5d5216fbb 100644 --- a/net/sched/sch_dsmark.c +++ b/net/sched/sch_dsmark.c @@ -185,7 +185,8 @@ ignore: } } -static struct tcf_block *dsmark_tcf_block(struct Qdisc *sch, unsigned long cl) +static struct tcf_block *dsmark_tcf_block(struct Qdisc *sch, unsigned long cl, + struct netlink_ext_ack *extack) { struct dsmark_qdisc_data *p = qdisc_priv(sch); diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c index b4ca46aafb5a..06e5360c54d8 100644 --- a/net/sched/sch_fq_codel.c +++ b/net/sched/sch_fq_codel.c @@ -597,7 +597,8 @@ static void fq_codel_unbind(struct Qdisc *q, unsigned long cl) { } -static struct tcf_block *fq_codel_tcf_block(struct Qdisc *sch, unsigned long cl) +static struct tcf_block *fq_codel_tcf_block(struct Qdisc *sch, unsigned long cl, + struct netlink_ext_ack *extack) { struct fq_codel_sched_data *q = qdisc_priv(sch); diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index 11410b0e4068..961668d657a0 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -1247,7 +1247,8 @@ hfsc_unbind_tcf(struct Qdisc *sch, unsigned long arg) cl->filter_cnt--; } -static struct tcf_block *hfsc_tcf_block(struct Qdisc *sch, unsigned long arg) +static struct tcf_block *hfsc_tcf_block(struct Qdisc *sch, unsigned long arg, + struct netlink_ext_ack *extack) { struct hfsc_sched *q = qdisc_priv(sch); struct hfsc_class *cl = (struct hfsc_class *)arg; diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index eb535a23a69b..79cf24468a38 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -1525,7 +1525,8 @@ failure: return err; } -static struct tcf_block *htb_tcf_block(struct Qdisc *sch, unsigned long arg) +static struct tcf_block *htb_tcf_block(struct Qdisc *sch, unsigned long arg, + struct netlink_ext_ack *extack) { struct htb_sched *q = qdisc_priv(sch); struct htb_class *cl = (struct htb_class *)arg; diff --git a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c index a6f175e64016..b9de7be531dd 100644 --- a/net/sched/sch_ingress.c +++ b/net/sched/sch_ingress.c @@ -48,7 +48,8 @@ static void ingress_walk(struct Qdisc *sch, struct qdisc_walker *walker) { } -static struct tcf_block *ingress_tcf_block(struct Qdisc *sch, unsigned long cl) +static struct tcf_block *ingress_tcf_block(struct Qdisc *sch, unsigned long cl, + struct netlink_ext_ack *extack) { struct ingress_sched_data *q = qdisc_priv(sch); @@ -154,7 +155,8 @@ static unsigned long clsact_bind_filter(struct Qdisc *sch, return clsact_find(sch, classid); } -static struct tcf_block *clsact_tcf_block(struct Qdisc *sch, unsigned long cl) +static struct tcf_block *clsact_tcf_block(struct Qdisc *sch, unsigned long cl, + struct netlink_ext_ack *extack) { struct clsact_sched_data *q = qdisc_priv(sch); diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c index a8db1dbeb04f..4bcbd3636606 100644 --- a/net/sched/sch_multiq.c +++ b/net/sched/sch_multiq.c @@ -371,7 +371,8 @@ static void multiq_walk(struct Qdisc *sch, struct qdisc_walker *arg) } } -static struct tcf_block *multiq_tcf_block(struct Qdisc *sch, unsigned long cl) +static struct tcf_block *multiq_tcf_block(struct Qdisc *sch, unsigned long cl, + struct netlink_ext_ack *extack) { struct multiq_sched_data *q = qdisc_priv(sch); diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index 5f8ecbaa2610..077af4730749 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -329,7 +329,8 @@ static void prio_walk(struct Qdisc *sch, struct qdisc_walker *arg) } } -static struct tcf_block *prio_tcf_block(struct Qdisc *sch, unsigned long cl) +static struct tcf_block *prio_tcf_block(struct Qdisc *sch, unsigned long cl, + struct netlink_ext_ack *extack) { struct prio_sched_data *q = qdisc_priv(sch); diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index 1f4a84b687d2..e77e7131e620 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c @@ -565,7 +565,8 @@ static unsigned long qfq_search_class(struct Qdisc *sch, u32 classid) return (unsigned long)qfq_find_class(sch, classid); } -static struct tcf_block *qfq_tcf_block(struct Qdisc *sch, unsigned long cl) +static struct tcf_block *qfq_tcf_block(struct Qdisc *sch, unsigned long cl, + struct netlink_ext_ack *extack) { struct qfq_sched *q = qdisc_priv(sch); diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c index d70d470361be..9e01b80edfe7 100644 --- a/net/sched/sch_sfb.c +++ b/net/sched/sch_sfb.c @@ -668,7 +668,8 @@ static void sfb_walk(struct Qdisc *sch, struct qdisc_walker *walker) } } -static struct tcf_block *sfb_tcf_block(struct Qdisc *sch, unsigned long cl) +static struct tcf_block *sfb_tcf_block(struct Qdisc *sch, unsigned long cl, + struct netlink_ext_ack *extack) { struct sfb_sched_data *q = qdisc_priv(sch); diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c index 3b5869c7b3f3..7a217be39f2a 100644 --- a/net/sched/sch_sfq.c +++ b/net/sched/sch_sfq.c @@ -837,7 +837,8 @@ static void sfq_unbind(struct Qdisc *q, unsigned long cl) { } -static struct tcf_block *sfq_tcf_block(struct Qdisc *sch, unsigned long cl) +static struct tcf_block *sfq_tcf_block(struct Qdisc *sch, unsigned long cl, + struct netlink_ext_ack *extack) { struct sfq_sched_data *q = qdisc_priv(sch); From 653d6fd68d8e5b43d496ca8a1d38331d515a226b Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 20 Dec 2017 12:35:17 -0500 Subject: [PATCH 07/14] net: sched: sch: add extack for graft callback This patch adds extack support for graft callback to prepare per-qdisc specific changes for extack. Cc: David Ahern Acked-by: Jamal Hadi Salim Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- include/net/sch_generic.h | 3 ++- net/sched/sch_api.c | 3 ++- net/sched/sch_atm.c | 3 ++- net/sched/sch_cbq.c | 2 +- net/sched/sch_drr.c | 3 ++- net/sched/sch_dsmark.c | 3 ++- net/sched/sch_hfsc.c | 2 +- net/sched/sch_htb.c | 2 +- net/sched/sch_mq.c | 2 +- net/sched/sch_mqprio.c | 2 +- net/sched/sch_multiq.c | 2 +- net/sched/sch_netem.c | 2 +- net/sched/sch_prio.c | 2 +- net/sched/sch_qfq.c | 3 ++- net/sched/sch_red.c | 2 +- net/sched/sch_sfb.c | 2 +- net/sched/sch_tbf.c | 2 +- 17 files changed, 23 insertions(+), 17 deletions(-) diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index f65dd2837142..3baadac9e7a5 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -151,7 +151,8 @@ struct Qdisc_class_ops { /* Child qdisc manipulation */ struct netdev_queue * (*select_queue)(struct Qdisc *, struct tcmsg *); int (*graft)(struct Qdisc *, unsigned long cl, - struct Qdisc *, struct Qdisc **); + struct Qdisc *, struct Qdisc **, + struct netlink_ext_ack *extack); struct Qdisc * (*leaf)(struct Qdisc *, unsigned long cl); void (*qlen_notify)(struct Qdisc *, unsigned long); diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 8c8c15b4da3b..4b950d72d13b 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -977,7 +977,8 @@ skip: unsigned long cl = cops->find(parent, classid); if (cl) { - err = cops->graft(parent, cl, new, &old); + err = cops->graft(parent, cl, new, &old, + extack); } else { NL_SET_ERR_MSG(extack, "Specified class not found"); err = -ENOENT; diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c index b606a75af333..8972ab72cda5 100644 --- a/net/sched/sch_atm.c +++ b/net/sched/sch_atm.c @@ -82,7 +82,8 @@ static inline struct atm_flow_data *lookup_flow(struct Qdisc *sch, u32 classid) } static int atm_tc_graft(struct Qdisc *sch, unsigned long arg, - struct Qdisc *new, struct Qdisc **old) + struct Qdisc *new, struct Qdisc **old, + struct netlink_ext_ack *extack) { struct atm_qdisc_data *p = qdisc_priv(sch); struct atm_flow_data *flow = (struct atm_flow_data *)arg; diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index d46048a439a6..bb7e4ccd7caf 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -1371,7 +1371,7 @@ cbq_dump_class_stats(struct Qdisc *sch, unsigned long arg, } static int cbq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, - struct Qdisc **old) + struct Qdisc **old, struct netlink_ext_ack *extack) { struct cbq_class *cl = (struct cbq_class *)arg; diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c index 44a2870f6f10..30e9cba54ddb 100644 --- a/net/sched/sch_drr.c +++ b/net/sched/sch_drr.c @@ -203,7 +203,8 @@ static void drr_unbind_tcf(struct Qdisc *sch, unsigned long arg) } static int drr_graft_class(struct Qdisc *sch, unsigned long arg, - struct Qdisc *new, struct Qdisc **old) + struct Qdisc *new, struct Qdisc **old, + struct netlink_ext_ack *extack) { struct drr_class *cl = (struct drr_class *)arg; diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c index 5dc5d5216fbb..92a36aa4c713 100644 --- a/net/sched/sch_dsmark.c +++ b/net/sched/sch_dsmark.c @@ -61,7 +61,8 @@ static inline int dsmark_valid_index(struct dsmark_qdisc_data *p, u16 index) /* ------------------------- Class/flow operations ------------------------- */ static int dsmark_graft(struct Qdisc *sch, unsigned long arg, - struct Qdisc *new, struct Qdisc **old) + struct Qdisc *new, struct Qdisc **old, + struct netlink_ext_ack *extack) { struct dsmark_qdisc_data *p = qdisc_priv(sch); diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index 961668d657a0..7f6a06ac4b9f 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -1177,7 +1177,7 @@ hfsc_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr) static int hfsc_graft_class(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, - struct Qdisc **old) + struct Qdisc **old, struct netlink_ext_ack *extack) { struct hfsc_class *cl = (struct hfsc_class *)arg; diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 79cf24468a38..65762d57a70d 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -1172,7 +1172,7 @@ htb_dump_class_stats(struct Qdisc *sch, unsigned long arg, struct gnet_dump *d) } static int htb_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, - struct Qdisc **old) + struct Qdisc **old, struct netlink_ext_ack *extack) { struct htb_class *cl = (struct htb_class *)arg; diff --git a/net/sched/sch_mq.c b/net/sched/sch_mq.c index b91f7d8cb184..50292e470432 100644 --- a/net/sched/sch_mq.c +++ b/net/sched/sch_mq.c @@ -155,7 +155,7 @@ static struct netdev_queue *mq_select_queue(struct Qdisc *sch, } static int mq_graft(struct Qdisc *sch, unsigned long cl, struct Qdisc *new, - struct Qdisc **old) + struct Qdisc **old, struct netlink_ext_ack *extack) { struct netdev_queue *dev_queue = mq_queue_get(sch, cl); struct net_device *dev = qdisc_dev(sch); diff --git a/net/sched/sch_mqprio.c b/net/sched/sch_mqprio.c index 0379fc4ee7bb..29071cf329f3 100644 --- a/net/sched/sch_mqprio.c +++ b/net/sched/sch_mqprio.c @@ -320,7 +320,7 @@ static struct netdev_queue *mqprio_queue_get(struct Qdisc *sch, } static int mqprio_graft(struct Qdisc *sch, unsigned long cl, struct Qdisc *new, - struct Qdisc **old) + struct Qdisc **old, struct netlink_ext_ack *extack) { struct net_device *dev = qdisc_dev(sch); struct netdev_queue *dev_queue = mqprio_queue_get(sch, cl); diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c index 4bcbd3636606..177d86de4b32 100644 --- a/net/sched/sch_multiq.c +++ b/net/sched/sch_multiq.c @@ -283,7 +283,7 @@ nla_put_failure: } static int multiq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, - struct Qdisc **old) + struct Qdisc **old, struct netlink_ext_ack *extack) { struct multiq_sched_data *q = qdisc_priv(sch); unsigned long band = arg - 1; diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index f45040b55531..7bbc13b8ca47 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -1159,7 +1159,7 @@ static int netem_dump_class(struct Qdisc *sch, unsigned long cl, } static int netem_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, - struct Qdisc **old) + struct Qdisc **old, struct netlink_ext_ack *extack) { struct netem_sched_data *q = qdisc_priv(sch); diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index 077af4730749..8fbd65661d77 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -242,7 +242,7 @@ nla_put_failure: } static int prio_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, - struct Qdisc **old) + struct Qdisc **old, struct netlink_ext_ack *extack) { struct prio_sched_data *q = qdisc_priv(sch); unsigned long band = arg - 1; diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index e77e7131e620..7ec893f770d2 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c @@ -595,7 +595,8 @@ static void qfq_unbind_tcf(struct Qdisc *sch, unsigned long arg) } static int qfq_graft_class(struct Qdisc *sch, unsigned long arg, - struct Qdisc *new, struct Qdisc **old) + struct Qdisc *new, struct Qdisc **old, + struct netlink_ext_ack *extack) { struct qfq_class *cl = (struct qfq_class *)arg; diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c index 6b85f8334b74..ea7d400b9eb2 100644 --- a/net/sched/sch_red.c +++ b/net/sched/sch_red.c @@ -382,7 +382,7 @@ static int red_dump_class(struct Qdisc *sch, unsigned long cl, } static int red_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, - struct Qdisc **old) + struct Qdisc **old, struct netlink_ext_ack *extack) { struct red_sched_data *q = qdisc_priv(sch); diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c index 9e01b80edfe7..1a33d6c3ac42 100644 --- a/net/sched/sch_sfb.c +++ b/net/sched/sch_sfb.c @@ -617,7 +617,7 @@ static int sfb_dump_class(struct Qdisc *sch, unsigned long cl, } static int sfb_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, - struct Qdisc **old) + struct Qdisc **old, struct netlink_ext_ack *extack) { struct sfb_sched_data *q = qdisc_priv(sch); diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index 273228eb5ce0..db6bd23530d4 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c @@ -496,7 +496,7 @@ static int tbf_dump_class(struct Qdisc *sch, unsigned long cl, } static int tbf_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, - struct Qdisc **old) + struct Qdisc **old, struct netlink_ext_ack *extack) { struct tbf_sched_data *q = qdisc_priv(sch); From e9bc3fa28bae7612f41e3538f241a2f87f629c94 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 20 Dec 2017 12:35:18 -0500 Subject: [PATCH 08/14] net: sch: api: add extack support in qdisc_get_rtab This patch adds extack support for the function qdisc_get_rtab 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_get_rtab failed. Cc: David Ahern Acked-by: Jamal Hadi Salim Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- include/net/pkt_sched.h | 3 ++- net/sched/act_police.c | 4 ++-- net/sched/sch_api.c | 9 +++++++-- net/sched/sch_cbq.c | 7 ++++--- net/sched/sch_htb.c | 6 ++++-- net/sched/sch_tbf.c | 6 ++++-- 6 files changed, 23 insertions(+), 12 deletions(-) diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index 240469228851..a4f21c0b4a43 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h @@ -101,7 +101,8 @@ 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); struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, - struct nlattr *tab); + struct nlattr *tab, + struct netlink_ext_ack *extack); void qdisc_put_rtab(struct qdisc_rate_table *tab); void qdisc_put_stab(struct qdisc_size_table *tab); void qdisc_warn_nonwc(const char *txt, struct Qdisc *qdisc); diff --git a/net/sched/act_police.c b/net/sched/act_police.c index bf483db993a1..95d3c9097b25 100644 --- a/net/sched/act_police.c +++ b/net/sched/act_police.c @@ -118,13 +118,13 @@ static int tcf_act_police_init(struct net *net, struct nlattr *nla, police = to_police(*a); if (parm->rate.rate) { err = -ENOMEM; - R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE]); + R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE], NULL); if (R_tab == NULL) goto failure; if (parm->peakrate.rate) { P_tab = qdisc_get_rtab(&parm->peakrate, - tb[TCA_POLICE_PEAKRATE]); + tb[TCA_POLICE_PEAKRATE], NULL); if (P_tab == NULL) goto failure; } diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 4b950d72d13b..79a9fdf9471d 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -393,13 +393,16 @@ static __u8 __detect_linklayer(struct tc_ratespec *r, __u32 *rtab) static struct qdisc_rate_table *qdisc_rtab_list; struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, - struct nlattr *tab) + struct nlattr *tab, + struct netlink_ext_ack *extack) { struct qdisc_rate_table *rtab; if (tab == NULL || r->rate == 0 || r->cell_log == 0 || - nla_len(tab) != TC_RTAB_SIZE) + nla_len(tab) != TC_RTAB_SIZE) { + NL_SET_ERR_MSG(extack, "Invalid rate table parameters for searching"); return NULL; + } for (rtab = qdisc_rtab_list; rtab; rtab = rtab->next) { if (!memcmp(&rtab->rate, r, sizeof(struct tc_ratespec)) && @@ -418,6 +421,8 @@ struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, r->linklayer = __detect_linklayer(r, rtab->data); rtab->next = qdisc_rtab_list; qdisc_rtab_list = rtab; + } else { + NL_SET_ERR_MSG(extack, "Failed to allocate new qdisc rate table"); } return rtab; } diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index bb7e4ccd7caf..79f081eb6bb0 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -1156,7 +1156,7 @@ static int cbq_init(struct Qdisc *sch, struct nlattr *opt, r = nla_data(tb[TCA_CBQ_RATE]); - q->link.R_tab = qdisc_get_rtab(r, tb[TCA_CBQ_RTAB]); + q->link.R_tab = qdisc_get_rtab(r, tb[TCA_CBQ_RTAB], extack); if (!q->link.R_tab) return -EINVAL; @@ -1484,7 +1484,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t if (tb[TCA_CBQ_RATE]) { rtab = qdisc_get_rtab(nla_data(tb[TCA_CBQ_RATE]), - tb[TCA_CBQ_RTAB]); + tb[TCA_CBQ_RTAB], extack); if (rtab == NULL) return -EINVAL; } @@ -1537,7 +1537,8 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t if (!tb[TCA_CBQ_WRROPT] || !tb[TCA_CBQ_RATE] || !tb[TCA_CBQ_LSSOPT]) return -EINVAL; - rtab = qdisc_get_rtab(nla_data(tb[TCA_CBQ_RATE]), tb[TCA_CBQ_RTAB]); + rtab = qdisc_get_rtab(nla_data(tb[TCA_CBQ_RATE]), tb[TCA_CBQ_RTAB], + extack); if (rtab == NULL) return -EINVAL; diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 65762d57a70d..51be1b756e4e 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -1357,10 +1357,12 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, /* Keeping backward compatible with rate_table based iproute2 tc */ if (hopt->rate.linklayer == TC_LINKLAYER_UNAWARE) - qdisc_put_rtab(qdisc_get_rtab(&hopt->rate, tb[TCA_HTB_RTAB])); + qdisc_put_rtab(qdisc_get_rtab(&hopt->rate, tb[TCA_HTB_RTAB], + NULL)); if (hopt->ceil.linklayer == TC_LINKLAYER_UNAWARE) - qdisc_put_rtab(qdisc_get_rtab(&hopt->ceil, tb[TCA_HTB_CTAB])); + qdisc_put_rtab(qdisc_get_rtab(&hopt->ceil, tb[TCA_HTB_CTAB], + NULL)); if (!cl) { /* new class */ struct Qdisc *new_q; diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index db6bd23530d4..1ab53ff80f46 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c @@ -327,11 +327,13 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt, qopt = nla_data(tb[TCA_TBF_PARMS]); if (qopt->rate.linklayer == TC_LINKLAYER_UNAWARE) qdisc_put_rtab(qdisc_get_rtab(&qopt->rate, - tb[TCA_TBF_RTAB])); + tb[TCA_TBF_RTAB], + NULL)); if (qopt->peakrate.linklayer == TC_LINKLAYER_UNAWARE) qdisc_put_rtab(qdisc_get_rtab(&qopt->peakrate, - tb[TCA_TBF_PTAB])); + tb[TCA_TBF_PTAB], + NULL)); buffer = min_t(u64, PSCHED_TICKS2NS(qopt->buffer), ~0U); mtu = min_t(u64, PSCHED_TICKS2NS(qopt->mtu), ~0U); From 8d1a77f974ca61d39afa5bf0aeab210525d31475 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 20 Dec 2017 12:35:19 -0500 Subject: [PATCH 09/14] net: sch: api: add extack support in tcf_block_get This patch adds extack support for the function tcf_block_get 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 tcf_block_get failed. Cc: David Ahern Acked-by: Jamal Hadi Salim Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- include/net/pkt_cls.h | 6 ++++-- net/sched/cls_api.c | 13 +++++++++---- net/sched/sch_atm.c | 6 ++++-- net/sched/sch_cbq.c | 4 ++-- net/sched/sch_drr.c | 2 +- net/sched/sch_dsmark.c | 2 +- net/sched/sch_fq_codel.c | 2 +- net/sched/sch_hfsc.c | 4 ++-- net/sched/sch_htb.c | 4 ++-- net/sched/sch_ingress.c | 8 +++++--- net/sched/sch_multiq.c | 2 +- net/sched/sch_prio.c | 2 +- net/sched/sch_qfq.c | 2 +- net/sched/sch_sfb.c | 2 +- net/sched/sch_sfq.c | 2 +- 15 files changed, 36 insertions(+), 25 deletions(-) diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h index 0105445cab83..58bba9c769ea 100644 --- a/include/net/pkt_cls.h +++ b/include/net/pkt_cls.h @@ -39,9 +39,11 @@ struct tcf_chain *tcf_chain_get(struct tcf_block *block, u32 chain_index, bool create); void tcf_chain_put(struct tcf_chain *chain); int tcf_block_get(struct tcf_block **p_block, - struct tcf_proto __rcu **p_filter_chain, struct Qdisc *q); + struct tcf_proto __rcu **p_filter_chain, struct Qdisc *q, + struct netlink_ext_ack *extack); int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q, - struct tcf_block_ext_info *ei); + struct tcf_block_ext_info *ei, + struct netlink_ext_ack *extack); void tcf_block_put(struct tcf_block *block); void tcf_block_put_ext(struct tcf_block *block, struct Qdisc *q, struct tcf_block_ext_info *ei); diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 22b977d40e1d..4591b87eaab5 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -281,20 +281,24 @@ static void tcf_block_offload_unbind(struct tcf_block *block, struct Qdisc *q, } int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q, - struct tcf_block_ext_info *ei) + struct tcf_block_ext_info *ei, + struct netlink_ext_ack *extack) { struct tcf_block *block = kzalloc(sizeof(*block), GFP_KERNEL); struct tcf_chain *chain; int err; - if (!block) + if (!block) { + NL_SET_ERR_MSG(extack, "Memory allocation for block failed"); return -ENOMEM; + } INIT_LIST_HEAD(&block->chain_list); INIT_LIST_HEAD(&block->cb_list); /* Create chain 0 by default, it has to be always present. */ chain = tcf_chain_create(block, 0); if (!chain) { + NL_SET_ERR_MSG(extack, "Failed to create new tcf chain"); err = -ENOMEM; goto err_chain_create; } @@ -321,7 +325,8 @@ static void tcf_chain_head_change_dflt(struct tcf_proto *tp_head, void *priv) } int tcf_block_get(struct tcf_block **p_block, - struct tcf_proto __rcu **p_filter_chain, struct Qdisc *q) + struct tcf_proto __rcu **p_filter_chain, struct Qdisc *q, + struct netlink_ext_ack *extack) { struct tcf_block_ext_info ei = { .chain_head_change = tcf_chain_head_change_dflt, @@ -329,7 +334,7 @@ int tcf_block_get(struct tcf_block **p_block, }; WARN_ON(!p_filter_chain); - return tcf_block_get_ext(p_block, q, &ei); + return tcf_block_get_ext(p_block, q, &ei, extack); } EXPORT_SYMBOL(tcf_block_get); diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c index 8972ab72cda5..493d5c25d83a 100644 --- a/net/sched/sch_atm.c +++ b/net/sched/sch_atm.c @@ -283,7 +283,8 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent, goto err_out; } - error = tcf_block_get(&flow->block, &flow->filter_list, sch); + error = tcf_block_get(&flow->block, &flow->filter_list, sch, + extack); if (error) { kfree(flow); goto err_out; @@ -550,7 +551,8 @@ static int atm_tc_init(struct Qdisc *sch, struct nlattr *opt, p->link.q = &noop_qdisc; pr_debug("atm_tc_init: link (%p) qdisc %p\n", &p->link, p->link.q); - err = tcf_block_get(&p->link.block, &p->link.filter_list, sch); + err = tcf_block_get(&p->link.block, &p->link.filter_list, sch, + extack); if (err) return err; diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index 79f081eb6bb0..248ea26997b9 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -1160,7 +1160,7 @@ static int cbq_init(struct Qdisc *sch, struct nlattr *opt, if (!q->link.R_tab) return -EINVAL; - err = tcf_block_get(&q->link.block, &q->link.filter_list, sch); + err = tcf_block_get(&q->link.block, &q->link.filter_list, sch, extack); if (err) goto put_rtab; @@ -1576,7 +1576,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t if (cl == NULL) goto failure; - err = tcf_block_get(&cl->block, &cl->filter_list, sch); + err = tcf_block_get(&cl->block, &cl->filter_list, sch, extack); if (err) { kfree(cl); return err; diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c index 30e9cba54ddb..9dfff065e27d 100644 --- a/net/sched/sch_drr.c +++ b/net/sched/sch_drr.c @@ -417,7 +417,7 @@ static int drr_init_qdisc(struct Qdisc *sch, struct nlattr *opt, struct drr_sched *q = qdisc_priv(sch); int err; - err = tcf_block_get(&q->block, &q->filter_list, sch); + err = tcf_block_get(&q->block, &q->filter_list, sch, extack); if (err) return err; err = qdisc_class_hash_init(&q->clhash); diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c index 92a36aa4c713..63f523b5e282 100644 --- a/net/sched/sch_dsmark.c +++ b/net/sched/sch_dsmark.c @@ -348,7 +348,7 @@ static int dsmark_init(struct Qdisc *sch, struct nlattr *opt, if (!opt) goto errout; - err = tcf_block_get(&p->block, &p->filter_list, sch); + err = tcf_block_get(&p->block, &p->filter_list, sch, extack); if (err) return err; diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c index 06e5360c54d8..22fa13cf5d8b 100644 --- a/net/sched/sch_fq_codel.c +++ b/net/sched/sch_fq_codel.c @@ -484,7 +484,7 @@ static int fq_codel_init(struct Qdisc *sch, struct nlattr *opt, return err; } - err = tcf_block_get(&q->block, &q->filter_list, sch); + err = tcf_block_get(&q->block, &q->filter_list, sch, extack); if (err) return err; diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index 7f6a06ac4b9f..9ae288fcbed8 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -1034,7 +1034,7 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, if (cl == NULL) return -ENOBUFS; - err = tcf_block_get(&cl->block, &cl->filter_list, sch); + err = tcf_block_get(&cl->block, &cl->filter_list, sch, extack); if (err) { kfree(cl); return err; @@ -1409,7 +1409,7 @@ hfsc_init_qdisc(struct Qdisc *sch, struct nlattr *opt, return err; q->eligible = RB_ROOT; - err = tcf_block_get(&q->root.block, &q->root.filter_list, sch); + err = tcf_block_get(&q->root.block, &q->root.filter_list, sch, extack); if (err) return err; diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 51be1b756e4e..54e1f860f1e5 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -1032,7 +1032,7 @@ static int htb_init(struct Qdisc *sch, struct nlattr *opt, if (!opt) return -EINVAL; - err = tcf_block_get(&q->block, &q->filter_list, sch); + err = tcf_block_get(&q->block, &q->filter_list, sch, extack); if (err) return err; @@ -1397,7 +1397,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, if (!cl) goto failure; - err = tcf_block_get(&cl->block, &cl->filter_list, sch); + err = tcf_block_get(&cl->block, &cl->filter_list, sch, extack); if (err) { kfree(cl); goto failure; diff --git a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c index b9de7be531dd..7ca2be20dd6f 100644 --- a/net/sched/sch_ingress.c +++ b/net/sched/sch_ingress.c @@ -78,7 +78,7 @@ static int ingress_init(struct Qdisc *sch, struct nlattr *opt, q->block_info.chain_head_change = clsact_chain_head_change; q->block_info.chain_head_change_priv = &q->miniqp; - err = tcf_block_get_ext(&q->block, sch, &q->block_info); + err = tcf_block_get_ext(&q->block, sch, &q->block_info, extack); if (err) return err; @@ -186,7 +186,8 @@ static int clsact_init(struct Qdisc *sch, struct nlattr *opt, q->ingress_block_info.chain_head_change = clsact_chain_head_change; q->ingress_block_info.chain_head_change_priv = &q->miniqp_ingress; - err = tcf_block_get_ext(&q->ingress_block, sch, &q->ingress_block_info); + err = tcf_block_get_ext(&q->ingress_block, sch, &q->ingress_block_info, + extack); if (err) return err; @@ -196,7 +197,8 @@ static int clsact_init(struct Qdisc *sch, struct nlattr *opt, q->egress_block_info.chain_head_change = clsact_chain_head_change; q->egress_block_info.chain_head_change_priv = &q->miniqp_egress; - err = tcf_block_get_ext(&q->egress_block, sch, &q->egress_block_info); + err = tcf_block_get_ext(&q->egress_block, sch, &q->egress_block_info, + extack); if (err) return err; diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c index 177d86de4b32..35cbaf8bd96a 100644 --- a/net/sched/sch_multiq.c +++ b/net/sched/sch_multiq.c @@ -248,7 +248,7 @@ static int multiq_init(struct Qdisc *sch, struct nlattr *opt, if (!opt) return -EINVAL; - err = tcf_block_get(&q->block, &q->filter_list, sch); + err = tcf_block_get(&q->block, &q->filter_list, sch, extack); if (err) return err; diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index 8fbd65661d77..502352762f03 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -215,7 +215,7 @@ static int prio_init(struct Qdisc *sch, struct nlattr *opt, if (!opt) return -EINVAL; - err = tcf_block_get(&q->block, &q->filter_list, sch); + err = tcf_block_get(&q->block, &q->filter_list, sch, extack); if (err) return err; diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index 7ec893f770d2..6ab58509cf49 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c @@ -1424,7 +1424,7 @@ static int qfq_init_qdisc(struct Qdisc *sch, struct nlattr *opt, int i, j, err; u32 max_cl_shift, maxbudg_shift, max_classes; - err = tcf_block_get(&q->block, &q->filter_list, sch); + err = tcf_block_get(&q->block, &q->filter_list, sch, extack); if (err) return err; diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c index 1a33d6c3ac42..a1a11ded8e4f 100644 --- a/net/sched/sch_sfb.c +++ b/net/sched/sch_sfb.c @@ -556,7 +556,7 @@ static int sfb_init(struct Qdisc *sch, struct nlattr *opt, struct sfb_sched_data *q = qdisc_priv(sch); int err; - err = tcf_block_get(&q->block, &q->filter_list, sch); + err = tcf_block_get(&q->block, &q->filter_list, sch, extack); if (err) return err; diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c index 7a217be39f2a..2f2678197760 100644 --- a/net/sched/sch_sfq.c +++ b/net/sched/sch_sfq.c @@ -731,7 +731,7 @@ static int sfq_init(struct Qdisc *sch, struct nlattr *opt, q->sch = sch; timer_setup(&q->perturb_timer, sfq_perturbation, TIMER_DEFERRABLE); - err = tcf_block_get(&q->block, &q->filter_list, sch); + err = tcf_block_get(&q->block, &q->filter_list, sch, extack); if (err) return err; From d0bd684dddab51ed017ece0359f26b038ec31940 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 20 Dec 2017 12:35:20 -0500 Subject: [PATCH 10/14] net: sch: api: add extack support in qdisc_alloc This patch adds extack support for the function qdisc_alloc 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_alloc failed. Cc: David Ahern Acked-by: Jamal Hadi Salim Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- include/net/sch_generic.h | 3 ++- net/sched/sch_api.c | 2 +- net/sched/sch_generic.c | 6 ++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index 3baadac9e7a5..faf6b2dbc1b2 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -471,7 +471,8 @@ void qdisc_destroy(struct Qdisc *qdisc); void qdisc_tree_reduce_backlog(struct Qdisc *qdisc, unsigned int n, unsigned int len); 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 Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue, const struct Qdisc_ops *ops, u32 parentid); void __qdisc_calculate_pkt_len(struct sk_buff *skb, diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 79a9fdf9471d..3a3a1da6b071 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1052,7 +1052,7 @@ static struct Qdisc *qdisc_create(struct net_device *dev, goto err_out; } - sch = qdisc_alloc(dev_queue, ops); + sch = qdisc_alloc(dev_queue, ops, extack); if (IS_ERR(sch)) { err = PTR_ERR(sch); goto err_out2; diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 30bc38c5d7ae..34ef4366f8e0 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -755,7 +755,8 @@ static struct lock_class_key qdisc_tx_busylock; static struct lock_class_key qdisc_running_key; struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, - const struct Qdisc_ops *ops) + const struct Qdisc_ops *ops, + struct netlink_ext_ack *extack) { void *p; struct Qdisc *sch; @@ -764,6 +765,7 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, struct net_device *dev; if (!dev_queue) { + NL_SET_ERR_MSG(extack, "No device queue given"); err = -EINVAL; goto errout; } @@ -835,7 +837,7 @@ struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue, if (!try_module_get(ops->owner)) return NULL; - sch = qdisc_alloc(dev_queue, ops); + sch = qdisc_alloc(dev_queue, ops, NULL); if (IS_ERR(sch)) { module_put(ops->owner); return NULL; From a38a98821c939e67e5906bddbed1d15af5ca860d Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 20 Dec 2017 12:35:21 -0500 Subject: [PATCH 11/14] 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 Acked-by: Jamal Hadi Salim Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- include/net/pkt_sched.h | 3 ++- include/net/sch_generic.h | 3 ++- net/sched/sch_atm.c | 5 +++-- net/sched/sch_cbq.c | 9 +++++---- net/sched/sch_drr.c | 7 ++++--- net/sched/sch_dsmark.c | 5 +++-- net/sched/sch_fifo.c | 6 ++++-- net/sched/sch_generic.c | 15 +++++++++------ net/sched/sch_hfsc.c | 8 ++++---- net/sched/sch_htb.c | 9 +++++---- net/sched/sch_mq.c | 3 ++- net/sched/sch_mqprio.c | 2 +- net/sched/sch_multiq.c | 2 +- net/sched/sch_prio.c | 3 ++- net/sched/sch_qfq.c | 8 ++++---- net/sched/sch_red.c | 3 ++- net/sched/sch_sfb.c | 2 +- net/sched/sch_tbf.c | 3 ++- 18 files changed, 56 insertions(+), 40 deletions(-) diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index a4f21c0b4a43..e2c75f52557b 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h @@ -89,7 +89,8 @@ extern struct Qdisc_ops pfifo_head_drop_qdisc_ops; int fifo_set_limit(struct Qdisc *q, unsigned int limit); 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 unregister_qdisc(struct Qdisc_ops *qops); diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index faf6b2dbc1b2..ac029d5d88e4 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -474,7 +474,8 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, const struct Qdisc_ops *ops, struct netlink_ext_ack *extack); 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, const struct qdisc_size_table *stab); int skb_do_redirect(struct sk_buff *); diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c index 493d5c25d83a..cd49afca9617 100644 --- a/net/sched/sch_atm.c +++ b/net/sched/sch_atm.c @@ -290,7 +290,8 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent, 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) flow->q = &noop_qdisc; 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); list_add(&p->link.list, &p->flows); p->link.q = qdisc_create_dflt(sch->dev_queue, - &pfifo_qdisc_ops, sch->handle); + &pfifo_qdisc_ops, sch->handle, extack); if (!p->link.q) p->link.q = &noop_qdisc; pr_debug("atm_tc_init: link (%p) qdisc %p\n", &p->link, p->link.q); diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index 248ea26997b9..efe5bf15b031 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -1172,7 +1172,7 @@ static int cbq_init(struct Qdisc *sch, struct nlattr *opt, q->link.common.classid = sch->handle; q->link.qdisc = sch; q->link.q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, - sch->handle); + sch->handle, NULL); if (!q->link.q) q->link.q = &noop_qdisc; 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; if (new == NULL) { - new = qdisc_create_dflt(sch->dev_queue, - &pfifo_qdisc_ops, cl->common.classid); + new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, + cl->common.classid, extack); if (new == NULL) return -ENOBUFS; } @@ -1596,7 +1596,8 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t cl->R_tab = rtab; 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) cl->q = &noop_qdisc; else diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c index 9dfff065e27d..bf638ce57c50 100644 --- a/net/sched/sch_drr.c +++ b/net/sched/sch_drr.c @@ -114,7 +114,8 @@ static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid, cl->common.classid = classid; cl->quantum = quantum; cl->qdisc = qdisc_create_dflt(sch->dev_queue, - &pfifo_qdisc_ops, classid); + &pfifo_qdisc_ops, classid, + NULL); if (cl->qdisc == NULL) cl->qdisc = &noop_qdisc; else @@ -209,8 +210,8 @@ static int drr_graft_class(struct Qdisc *sch, unsigned long arg, struct drr_class *cl = (struct drr_class *)arg; if (new == NULL) { - new = qdisc_create_dflt(sch->dev_queue, - &pfifo_qdisc_ops, cl->common.classid); + new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, + cl->common.classid, NULL); if (new == NULL) new = &noop_qdisc; } diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c index 63f523b5e282..049714c57075 100644 --- a/net/sched/sch_dsmark.c +++ b/net/sched/sch_dsmark.c @@ -71,7 +71,7 @@ static int dsmark_graft(struct Qdisc *sch, unsigned long arg, if (new == NULL) { new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, - sch->handle); + sch->handle, NULL); if (new == NULL) new = &noop_qdisc; } @@ -381,7 +381,8 @@ static int dsmark_init(struct Qdisc *sch, struct nlattr *opt, p->default_index = default_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) p->q = &noop_qdisc; else diff --git a/net/sched/sch_fifo.c b/net/sched/sch_fifo.c index c65f23c70f40..24893d3b5d22 100644 --- a/net/sched/sch_fifo.c +++ b/net/sched/sch_fifo.c @@ -166,12 +166,14 @@ int fifo_set_limit(struct Qdisc *q, unsigned int limit) EXPORT_SYMBOL(fifo_set_limit); 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; 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) { err = fifo_set_limit(q, limit); if (err < 0) { diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 34ef4366f8e0..10aaa3b615ce 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -830,21 +830,24 @@ errout: struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue, const struct Qdisc_ops *ops, - unsigned int parentid) + unsigned int parentid, + struct netlink_ext_ack *extack) { 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; + } - sch = qdisc_alloc(dev_queue, ops, NULL); + sch = qdisc_alloc(dev_queue, ops, extack); if (IS_ERR(sch)) { module_put(ops->owner); return NULL; } sch->parent = parentid; - if (!ops->init || ops->init(sch, NULL, NULL) == 0) + if (!ops->init || ops->init(sch, NULL, extack) == 0) return 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) 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) { netdev_info(dev, "activation failed\n"); return; @@ -979,7 +982,7 @@ static void attach_default_qdiscs(struct net_device *dev) dev->qdisc = txq->qdisc_sleeping; qdisc_refcount_inc(dev->qdisc); } 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) { dev->qdisc = qdisc; qdisc->ops->attach(qdisc); diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index 9ae288fcbed8..3ae9877ea205 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -1062,8 +1062,8 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, cl->cl_common.classid = classid; cl->sched = q; cl->cl_parent = parent; - cl->qdisc = qdisc_create_dflt(sch->dev_queue, - &pfifo_qdisc_ops, classid); + cl->qdisc = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, + classid, NULL); if (cl->qdisc == NULL) cl->qdisc = &noop_qdisc; else @@ -1185,7 +1185,7 @@ hfsc_graft_class(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, return -EINVAL; if (new == NULL) { new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, - cl->cl_common.classid); + cl->cl_common.classid, NULL); if (new == NULL) 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.sched = q; q->root.qdisc = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, - sch->handle); + sch->handle, NULL); if (q->root.qdisc == NULL) q->root.qdisc = &noop_qdisc; else diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 54e1f860f1e5..1ea9846cc6ce 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -1180,7 +1180,7 @@ static int htb_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, return -EINVAL; if (new == NULL && (new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, - cl->common.classid)) == NULL) + cl->common.classid, extack)) == NULL) return -ENOBUFS; *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)) { new_q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, - cl->parent->common.classid); + cl->parent->common.classid, + NULL); 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 * -- thanks to Karlis Peisenieks */ - new_q = qdisc_create_dflt(sch->dev_queue, - &pfifo_qdisc_ops, classid); + new_q = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, + classid, NULL); sch_tree_lock(sch); if (parent && !parent->level) { unsigned int qlen = parent->un.leaf.q->q.qlen; diff --git a/net/sched/sch_mq.c b/net/sched/sch_mq.c index 50292e470432..f062a18e9162 100644 --- a/net/sched/sch_mq.c +++ b/net/sched/sch_mq.c @@ -61,7 +61,8 @@ static int mq_init(struct Qdisc *sch, struct nlattr *opt, dev_queue = netdev_get_tx_queue(dev, ntx); qdisc = qdisc_create_dflt(dev_queue, get_default_qdisc_ops(dev, ntx), TC_H_MAKE(TC_H_MAJ(sch->handle), - TC_H_MIN(ntx + 1))); + TC_H_MIN(ntx + 1)), + extack); if (!qdisc) return -ENOMEM; priv->qdiscs[ntx] = qdisc; diff --git a/net/sched/sch_mqprio.c b/net/sched/sch_mqprio.c index 29071cf329f3..0e9d761cdd80 100644 --- a/net/sched/sch_mqprio.c +++ b/net/sched/sch_mqprio.c @@ -230,7 +230,7 @@ static int mqprio_init(struct Qdisc *sch, struct nlattr *opt, qdisc = qdisc_create_dflt(dev_queue, get_default_qdisc_ops(dev, i), TC_H_MAKE(TC_H_MAJ(sch->handle), - TC_H_MIN(i + 1))); + TC_H_MIN(i + 1)), extack); if (!qdisc) return -ENOMEM; diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c index 35cbaf8bd96a..1da7ea8de0ad 100644 --- a/net/sched/sch_multiq.c +++ b/net/sched/sch_multiq.c @@ -216,7 +216,7 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt, child = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, TC_H_MAKE(sch->handle, - i + 1)); + i + 1), extack); if (child) { sch_tree_lock(sch); old = q->queues[i]; diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index 502352762f03..fe1510eb111f 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -176,7 +176,8 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt, /* Before commit, make sure we can allocate all new qdiscs */ for (i = oldbands; i < qopt->bands; i++) { 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]) { while (i > oldbands) qdisc_destroy(queues[--i]); diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index 6ab58509cf49..bb1a9c11fc54 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c @@ -480,8 +480,8 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, cl->common.classid = classid; cl->deficit = lmax; - cl->qdisc = qdisc_create_dflt(sch->dev_queue, - &pfifo_qdisc_ops, classid); + cl->qdisc = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, + classid, NULL); if (cl->qdisc == NULL) 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; if (new == NULL) { - new = qdisc_create_dflt(sch->dev_queue, - &pfifo_qdisc_ops, cl->common.classid); + new = qdisc_create_dflt(sch->dev_queue, &pfifo_qdisc_ops, + cl->common.classid, NULL); if (new == NULL) new = &noop_qdisc; } diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c index ea7d400b9eb2..ec0bd36e09a9 100644 --- a/net/sched/sch_red.c +++ b/net/sched/sch_red.c @@ -225,7 +225,8 @@ static int red_change(struct Qdisc *sch, struct nlattr *opt, return -EINVAL; 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)) return PTR_ERR(child); } diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c index a1a11ded8e4f..7cbdad8419b7 100644 --- a/net/sched/sch_sfb.c +++ b/net/sched/sch_sfb.c @@ -513,7 +513,7 @@ static int sfb_change(struct Qdisc *sch, struct nlattr *opt, if (limit == 0) 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)) return PTR_ERR(child); diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index 1ab53ff80f46..83e76d046993 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c @@ -386,7 +386,8 @@ static int tbf_change(struct Qdisc *sch, struct nlattr *opt, if (err) goto done; } 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)) { err = PTR_ERR(child); goto done; From 62a6de62dc57b1b8791db7504846057128e5ebd9 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 20 Dec 2017 12:35:22 -0500 Subject: [PATCH 12/14] net: sch: sch_cbq: add extack support This patch adds extack support for the cbq qdisc implementation by adding NL_SET_ERR_MSG in validation of user input. Also it serves to illustrate a use case of how the infrastructure ops api changes are to be used by individual qdiscs. Cc: David Ahern Acked-by: Jamal Hadi Salim Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- net/sched/sch_cbq.c | 46 +++++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index efe5bf15b031..f42025d53cfe 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -1144,15 +1144,19 @@ static int cbq_init(struct Qdisc *sch, struct nlattr *opt, hrtimer_init(&q->delay_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED); q->delay_timer.function = cbq_undelay; - if (!opt) + if (!opt) { + NL_SET_ERR_MSG(extack, "CBQ options are required for this operation"); return -EINVAL; + } - err = nla_parse_nested(tb, TCA_CBQ_MAX, opt, cbq_policy, NULL); + err = nla_parse_nested(tb, TCA_CBQ_MAX, opt, cbq_policy, extack); if (err < 0) return err; - if (!tb[TCA_CBQ_RTAB] || !tb[TCA_CBQ_RATE]) + if (!tb[TCA_CBQ_RTAB] || !tb[TCA_CBQ_RATE]) { + NL_SET_ERR_MSG(extack, "Rate specification missing or incomplete"); return -EINVAL; + } r = nla_data(tb[TCA_CBQ_RATE]); @@ -1462,24 +1466,32 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t struct cbq_class *parent; struct qdisc_rate_table *rtab = NULL; - if (!opt) + if (!opt) { + NL_SET_ERR_MSG(extack, "Mandatory qdisc options missing"); return -EINVAL; + } - err = nla_parse_nested(tb, TCA_CBQ_MAX, opt, cbq_policy, NULL); + err = nla_parse_nested(tb, TCA_CBQ_MAX, opt, cbq_policy, extack); if (err < 0) return err; - if (tb[TCA_CBQ_OVL_STRATEGY] || tb[TCA_CBQ_POLICE]) + if (tb[TCA_CBQ_OVL_STRATEGY] || tb[TCA_CBQ_POLICE]) { + NL_SET_ERR_MSG(extack, "Neither overlimit strategy nor policing attributes can be used for changing class params"); return -EOPNOTSUPP; + } if (cl) { /* Check parent */ if (parentid) { if (cl->tparent && - cl->tparent->common.classid != parentid) + cl->tparent->common.classid != parentid) { + NL_SET_ERR_MSG(extack, "Invalid parent id"); return -EINVAL; - if (!cl->tparent && parentid != TC_H_ROOT) + } + if (!cl->tparent && parentid != TC_H_ROOT) { + NL_SET_ERR_MSG(extack, "Parent must be root"); return -EINVAL; + } } if (tb[TCA_CBQ_RATE]) { @@ -1496,6 +1508,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t qdisc_root_sleeping_running(sch), tca[TCA_RATE]); if (err) { + NL_SET_ERR_MSG(extack, "Failed to replace specified rate estimator"); qdisc_put_rtab(rtab); return err; } @@ -1534,8 +1547,10 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t if (parentid == TC_H_ROOT) return -EINVAL; - if (!tb[TCA_CBQ_WRROPT] || !tb[TCA_CBQ_RATE] || !tb[TCA_CBQ_LSSOPT]) + if (!tb[TCA_CBQ_WRROPT] || !tb[TCA_CBQ_RATE] || !tb[TCA_CBQ_LSSOPT]) { + NL_SET_ERR_MSG(extack, "One of the following attributes MUST be specified: WRR, rate or link sharing"); return -EINVAL; + } rtab = qdisc_get_rtab(nla_data(tb[TCA_CBQ_RATE]), tb[TCA_CBQ_RTAB], extack); @@ -1545,8 +1560,10 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t if (classid) { err = -EINVAL; if (TC_H_MAJ(classid ^ sch->handle) || - cbq_class_lookup(q, classid)) + cbq_class_lookup(q, classid)) { + NL_SET_ERR_MSG(extack, "Specified class not found"); goto failure; + } } else { int i; classid = TC_H_MAKE(sch->handle, 0x8000); @@ -1558,8 +1575,10 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t break; } err = -ENOSR; - if (i >= 0x8000) + if (i >= 0x8000) { + NL_SET_ERR_MSG(extack, "Unable to generate classid"); goto failure; + } classid = classid|q->hgenerator; } @@ -1567,8 +1586,10 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t if (parentid) { parent = cbq_class_lookup(q, parentid); err = -EINVAL; - if (!parent) + if (!parent) { + NL_SET_ERR_MSG(extack, "Failed to find parentid"); goto failure; + } } err = -ENOBUFS; @@ -1588,6 +1609,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t qdisc_root_sleeping_running(sch), tca[TCA_RATE]); if (err) { + NL_SET_ERR_MSG(extack, "Couldn't create new estimator"); tcf_block_put(cl->block); kfree(cl); goto failure; From 710fb39689d194aa0acf7928f387487c25fb2b8f Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 20 Dec 2017 12:35:23 -0500 Subject: [PATCH 13/14] net: sch: sch_cbs: add extack support This patch adds extack support for the cbs qdisc implementation by adding NL_SET_ERR_MSG in validation of user input. Also it serves to illustrate a use case of how the infrastructure ops api changes are to be used by individual qdiscs. Cc: David Ahern Acked-by: Jamal Hadi Salim Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- net/sched/sch_cbs.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/net/sched/sch_cbs.c b/net/sched/sch_cbs.c index 8bf6e163d29c..cdd96b9a27bc 100644 --- a/net/sched/sch_cbs.c +++ b/net/sched/sch_cbs.c @@ -219,14 +219,17 @@ static void cbs_disable_offload(struct net_device *dev, } static int cbs_enable_offload(struct net_device *dev, struct cbs_sched_data *q, - const struct tc_cbs_qopt *opt) + const struct tc_cbs_qopt *opt, + struct netlink_ext_ack *extack) { const struct net_device_ops *ops = dev->netdev_ops; struct tc_cbs_qopt_offload cbs = { }; int err; - if (!ops->ndo_setup_tc) + if (!ops->ndo_setup_tc) { + NL_SET_ERR_MSG(extack, "Specified device does not support cbs offload"); return -EOPNOTSUPP; + } cbs.queue = q->queue; @@ -237,8 +240,10 @@ static int cbs_enable_offload(struct net_device *dev, struct cbs_sched_data *q, cbs.sendslope = opt->sendslope; err = ops->ndo_setup_tc(dev, TC_SETUP_QDISC_CBS, &cbs); - if (err < 0) + if (err < 0) { + NL_SET_ERR_MSG(extack, "Specified device failed to setup cbs hardware offload"); return err; + } q->enqueue = cbs_enqueue_offload; q->dequeue = cbs_dequeue_offload; @@ -255,12 +260,14 @@ static int cbs_change(struct Qdisc *sch, struct nlattr *opt, struct tc_cbs_qopt *qopt; int err; - err = nla_parse_nested(tb, TCA_CBS_MAX, opt, cbs_policy, NULL); + err = nla_parse_nested(tb, TCA_CBS_MAX, opt, cbs_policy, extack); if (err < 0) return err; - if (!tb[TCA_CBS_PARMS]) + if (!tb[TCA_CBS_PARMS]) { + NL_SET_ERR_MSG(extack, "Missing CBS parameter which are mandatory"); return -EINVAL; + } qopt = nla_data(tb[TCA_CBS_PARMS]); @@ -277,7 +284,7 @@ static int cbs_change(struct Qdisc *sch, struct nlattr *opt, cbs_disable_offload(dev, q); } else { - err = cbs_enable_offload(dev, q, qopt); + err = cbs_enable_offload(dev, q, qopt, extack); if (err < 0) return err; } @@ -298,8 +305,10 @@ static int cbs_init(struct Qdisc *sch, struct nlattr *opt, struct cbs_sched_data *q = qdisc_priv(sch); struct net_device *dev = qdisc_dev(sch); - if (!opt) + if (!opt) { + NL_SET_ERR_MSG(extack, "Missing CBS qdisc options which are mandatory"); return -EINVAL; + } q->queue = sch->dev_queue - netdev_get_tx_queue(dev, 0); From a7c31693e1054fe9af08bc404cdd687c327d0fa6 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 20 Dec 2017 12:35:24 -0500 Subject: [PATCH 14/14] net: sch: sch_drr: add extack support This patch adds extack support for the drr qdisc implementation by adding NL_SET_ERR_MSG in validation of user input. Also it serves to illustrate a use case of how the infrastructure ops api changes are to be used by individual qdiscs. Cc: David Ahern Acked-by: Jamal Hadi Salim Signed-off-by: Alexander Aring Signed-off-by: David S. Miller --- net/sched/sch_drr.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c index bf638ce57c50..e0b0cf8a9939 100644 --- a/net/sched/sch_drr.c +++ b/net/sched/sch_drr.c @@ -74,17 +74,21 @@ static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid, u32 quantum; int err; - if (!opt) + if (!opt) { + NL_SET_ERR_MSG(extack, "DRR options are required for this operation"); return -EINVAL; + } - err = nla_parse_nested(tb, TCA_DRR_MAX, opt, drr_policy, NULL); + err = nla_parse_nested(tb, TCA_DRR_MAX, opt, drr_policy, extack); if (err < 0) return err; if (tb[TCA_DRR_QUANTUM]) { quantum = nla_get_u32(tb[TCA_DRR_QUANTUM]); - if (quantum == 0) + if (quantum == 0) { + NL_SET_ERR_MSG(extack, "Specified DRR quantum cannot be zero"); return -EINVAL; + } } else quantum = psched_mtu(qdisc_dev(sch)); @@ -95,8 +99,10 @@ static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid, NULL, qdisc_root_sleeping_running(sch), tca[TCA_RATE]); - if (err) + if (err) { + NL_SET_ERR_MSG(extack, "Failed to replace estimator"); return err; + } } sch_tree_lock(sch); @@ -127,6 +133,7 @@ static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid, qdisc_root_sleeping_running(sch), tca[TCA_RATE]); if (err) { + NL_SET_ERR_MSG(extack, "Failed to replace estimator"); qdisc_destroy(cl->qdisc); kfree(cl); return err; @@ -179,8 +186,10 @@ static struct tcf_block *drr_tcf_block(struct Qdisc *sch, unsigned long cl, { struct drr_sched *q = qdisc_priv(sch); - if (cl) + if (cl) { + NL_SET_ERR_MSG(extack, "DRR classid must be zero"); return NULL; + } return q->block; }