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

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
Loading
Loading
Loading
Loading
+34 −12
Original line number Diff line number Diff line
@@ -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,25 +1466,33 @@ 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]) {
			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
						    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,9 +1586,11 @@ 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;
	cl = kzalloc(sizeof(*cl), GFP_KERNEL);
@@ -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;