Commit 62a6de62 authored by Alexander Aring's avatar Alexander Aring Committed by David S. Miller

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 <dsahern@gmail.com>
Acked-by: default avatarJamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: default avatarAlexander Aring <aring@mojatatu.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a38a9882
...@@ -1144,15 +1144,19 @@ static int cbq_init(struct Qdisc *sch, struct nlattr *opt, ...@@ -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); hrtimer_init(&q->delay_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED);
q->delay_timer.function = cbq_undelay; q->delay_timer.function = cbq_undelay;
if (!opt) if (!opt) {
NL_SET_ERR_MSG(extack, "CBQ options are required for this operation");
return -EINVAL; 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) if (err < 0)
return err; 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; return -EINVAL;
}
r = nla_data(tb[TCA_CBQ_RATE]); r = nla_data(tb[TCA_CBQ_RATE]);
...@@ -1462,25 +1466,33 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t ...@@ -1462,25 +1466,33 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
struct cbq_class *parent; struct cbq_class *parent;
struct qdisc_rate_table *rtab = NULL; struct qdisc_rate_table *rtab = NULL;
if (!opt) if (!opt) {
NL_SET_ERR_MSG(extack, "Mandatory qdisc options missing");
return -EINVAL; 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) if (err < 0)
return err; 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; return -EOPNOTSUPP;
}
if (cl) { if (cl) {
/* Check parent */ /* Check parent */
if (parentid) { if (parentid) {
if (cl->tparent && if (cl->tparent &&
cl->tparent->common.classid != parentid) cl->tparent->common.classid != parentid) {
NL_SET_ERR_MSG(extack, "Invalid parent id");
return -EINVAL; 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; return -EINVAL;
} }
}
if (tb[TCA_CBQ_RATE]) { if (tb[TCA_CBQ_RATE]) {
rtab = qdisc_get_rtab(nla_data(tb[TCA_CBQ_RATE]), rtab = qdisc_get_rtab(nla_data(tb[TCA_CBQ_RATE]),
...@@ -1496,6 +1508,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t ...@@ -1496,6 +1508,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
qdisc_root_sleeping_running(sch), qdisc_root_sleeping_running(sch),
tca[TCA_RATE]); tca[TCA_RATE]);
if (err) { if (err) {
NL_SET_ERR_MSG(extack, "Failed to replace specified rate estimator");
qdisc_put_rtab(rtab); qdisc_put_rtab(rtab);
return err; return err;
} }
...@@ -1534,8 +1547,10 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t ...@@ -1534,8 +1547,10 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
if (parentid == TC_H_ROOT) if (parentid == TC_H_ROOT)
return -EINVAL; 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; 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); extack);
...@@ -1545,8 +1560,10 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t ...@@ -1545,8 +1560,10 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
if (classid) { if (classid) {
err = -EINVAL; err = -EINVAL;
if (TC_H_MAJ(classid ^ sch->handle) || 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; goto failure;
}
} else { } else {
int i; int i;
classid = TC_H_MAKE(sch->handle, 0x8000); classid = TC_H_MAKE(sch->handle, 0x8000);
...@@ -1558,8 +1575,10 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t ...@@ -1558,8 +1575,10 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
break; break;
} }
err = -ENOSR; err = -ENOSR;
if (i >= 0x8000) if (i >= 0x8000) {
NL_SET_ERR_MSG(extack, "Unable to generate classid");
goto failure; goto failure;
}
classid = classid|q->hgenerator; classid = classid|q->hgenerator;
} }
...@@ -1567,9 +1586,11 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t ...@@ -1567,9 +1586,11 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
if (parentid) { if (parentid) {
parent = cbq_class_lookup(q, parentid); parent = cbq_class_lookup(q, parentid);
err = -EINVAL; err = -EINVAL;
if (!parent) if (!parent) {
NL_SET_ERR_MSG(extack, "Failed to find parentid");
goto failure; goto failure;
} }
}
err = -ENOBUFS; err = -ENOBUFS;
cl = kzalloc(sizeof(*cl), GFP_KERNEL); cl = kzalloc(sizeof(*cl), GFP_KERNEL);
...@@ -1588,6 +1609,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t ...@@ -1588,6 +1609,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t
qdisc_root_sleeping_running(sch), qdisc_root_sleeping_running(sch),
tca[TCA_RATE]); tca[TCA_RATE]);
if (err) { if (err) {
NL_SET_ERR_MSG(extack, "Couldn't create new estimator");
tcf_block_put(cl->block); tcf_block_put(cl->block);
kfree(cl); kfree(cl);
goto failure; goto failure;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment