net_sched: make cls_ops->change and cls_ops->delete optional

Some schedulers don't support creating, changing or deleting classes.
Make the respective callbacks optionally and consistently return
-EOPNOTSUPP for unsupported operations, instead of currently either
-EOPNOTSUPP, -ENOSYS or no error.

In case of sch_prio and sch_multiq, the removed operations additionally
checked for an invalid class. This is not necessary since the class
argument can only orginate from ->get() or in case of ->change is 0
for creation of new classes, in which case ->change() incorrectly
returned -ENOENT.

As a side-effect, this patch fixes a possible (root-only) NULL pointer
function call in sch_ingress, which didn't implement a so far mandatory
->delete() operation.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Patrick McHardy 2009-09-04 06:41:16 +00:00 committed by David S. Miller
parent 71ebe5e919
commit de6d5cdf88
7 changed files with 6 additions and 85 deletions

View file

@ -1417,7 +1417,9 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
goto out; goto out;
break; break;
case RTM_DELTCLASS: case RTM_DELTCLASS:
err = cops->delete(q, cl); err = -EOPNOTSUPP;
if (cops->delete)
err = cops->delete(q, cl);
if (err == 0) if (err == 0)
tclass_notify(skb, n, q, cl, RTM_DELTCLASS); tclass_notify(skb, n, q, cl, RTM_DELTCLASS);
goto out; goto out;
@ -1431,7 +1433,9 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
} }
new_cl = cl; new_cl = cl;
err = cops->change(q, clid, pid, tca, &new_cl); err = -EOPNOTSUPP;
if (cops->change)
err = cops->change(q, clid, pid, tca, &new_cl);
if (err == 0) if (err == 0)
tclass_notify(skb, n, q, new_cl, RTM_NEWTCLASS); tclass_notify(skb, n, q, new_cl, RTM_NEWTCLASS);

View file

@ -42,12 +42,6 @@ static void ingress_put(struct Qdisc *sch, unsigned long cl)
{ {
} }
static int ingress_change(struct Qdisc *sch, u32 classid, u32 parent,
struct nlattr **tca, unsigned long *arg)
{
return 0;
}
static void ingress_walk(struct Qdisc *sch, struct qdisc_walker *walker) static void ingress_walk(struct Qdisc *sch, struct qdisc_walker *walker)
{ {
return; return;
@ -120,7 +114,6 @@ static const struct Qdisc_class_ops ingress_class_ops = {
.leaf = ingress_leaf, .leaf = ingress_leaf,
.get = ingress_get, .get = ingress_get,
.put = ingress_put, .put = ingress_put,
.change = ingress_change,
.walk = ingress_walk, .walk = ingress_walk,
.tcf_chain = ingress_find_tcf, .tcf_chain = ingress_find_tcf,
.bind_tcf = ingress_bind_filter, .bind_tcf = ingress_bind_filter,

View file

@ -348,26 +348,6 @@ static void multiq_put(struct Qdisc *q, unsigned long cl)
return; return;
} }
static int multiq_change(struct Qdisc *sch, u32 handle, u32 parent,
struct nlattr **tca, unsigned long *arg)
{
unsigned long cl = *arg;
struct multiq_sched_data *q = qdisc_priv(sch);
if (cl - 1 > q->bands)
return -ENOENT;
return 0;
}
static int multiq_delete(struct Qdisc *sch, unsigned long cl)
{
struct multiq_sched_data *q = qdisc_priv(sch);
if (cl - 1 > q->bands)
return -ENOENT;
return 0;
}
static int multiq_dump_class(struct Qdisc *sch, unsigned long cl, static int multiq_dump_class(struct Qdisc *sch, unsigned long cl,
struct sk_buff *skb, struct tcmsg *tcm) struct sk_buff *skb, struct tcmsg *tcm)
{ {
@ -430,8 +410,6 @@ static const struct Qdisc_class_ops multiq_class_ops = {
.leaf = multiq_leaf, .leaf = multiq_leaf,
.get = multiq_get, .get = multiq_get,
.put = multiq_put, .put = multiq_put,
.change = multiq_change,
.delete = multiq_delete,
.walk = multiq_walk, .walk = multiq_walk,
.tcf_chain = multiq_find_tcf, .tcf_chain = multiq_find_tcf,
.bind_tcf = multiq_bind, .bind_tcf = multiq_bind,

View file

@ -311,25 +311,6 @@ static void prio_put(struct Qdisc *q, unsigned long cl)
return; return;
} }
static int prio_change(struct Qdisc *sch, u32 handle, u32 parent, struct nlattr **tca, unsigned long *arg)
{
unsigned long cl = *arg;
struct prio_sched_data *q = qdisc_priv(sch);
if (cl - 1 > q->bands)
return -ENOENT;
return 0;
}
static int prio_delete(struct Qdisc *sch, unsigned long cl)
{
struct prio_sched_data *q = qdisc_priv(sch);
if (cl - 1 > q->bands)
return -ENOENT;
return 0;
}
static int prio_dump_class(struct Qdisc *sch, unsigned long cl, struct sk_buff *skb, static int prio_dump_class(struct Qdisc *sch, unsigned long cl, struct sk_buff *skb,
struct tcmsg *tcm) struct tcmsg *tcm)
{ {
@ -392,8 +373,6 @@ static const struct Qdisc_class_ops prio_class_ops = {
.leaf = prio_leaf, .leaf = prio_leaf,
.get = prio_get, .get = prio_get,
.put = prio_put, .put = prio_put,
.change = prio_change,
.delete = prio_delete,
.walk = prio_walk, .walk = prio_walk,
.tcf_chain = prio_find_tcf, .tcf_chain = prio_find_tcf,
.bind_tcf = prio_bind, .bind_tcf = prio_bind,

View file

@ -308,17 +308,6 @@ static void red_put(struct Qdisc *sch, unsigned long arg)
return; return;
} }
static int red_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
struct nlattr **tca, unsigned long *arg)
{
return -ENOSYS;
}
static int red_delete(struct Qdisc *sch, unsigned long cl)
{
return -ENOSYS;
}
static void red_walk(struct Qdisc *sch, struct qdisc_walker *walker) static void red_walk(struct Qdisc *sch, struct qdisc_walker *walker)
{ {
if (!walker->stop) { if (!walker->stop) {
@ -336,8 +325,6 @@ static const struct Qdisc_class_ops red_class_ops = {
.leaf = red_leaf, .leaf = red_leaf,
.get = red_get, .get = red_get,
.put = red_put, .put = red_put,
.change = red_change_class,
.delete = red_delete,
.walk = red_walk, .walk = red_walk,
.dump = red_dump_class, .dump = red_dump_class,
}; };

View file

@ -496,12 +496,6 @@ nla_put_failure:
return -1; return -1;
} }
static int sfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
struct nlattr **tca, unsigned long *arg)
{
return -EOPNOTSUPP;
}
static unsigned long sfq_get(struct Qdisc *sch, u32 classid) static unsigned long sfq_get(struct Qdisc *sch, u32 classid)
{ {
return 0; return 0;
@ -560,7 +554,6 @@ static void sfq_walk(struct Qdisc *sch, struct qdisc_walker *arg)
static const struct Qdisc_class_ops sfq_class_ops = { static const struct Qdisc_class_ops sfq_class_ops = {
.get = sfq_get, .get = sfq_get,
.change = sfq_change_class,
.tcf_chain = sfq_find_tcf, .tcf_chain = sfq_find_tcf,
.dump = sfq_dump_class, .dump = sfq_dump_class,
.dump_stats = sfq_dump_class_stats, .dump_stats = sfq_dump_class_stats,

View file

@ -410,17 +410,6 @@ static void tbf_put(struct Qdisc *sch, unsigned long arg)
{ {
} }
static int tbf_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
struct nlattr **tca, unsigned long *arg)
{
return -ENOSYS;
}
static int tbf_delete(struct Qdisc *sch, unsigned long arg)
{
return -ENOSYS;
}
static void tbf_walk(struct Qdisc *sch, struct qdisc_walker *walker) static void tbf_walk(struct Qdisc *sch, struct qdisc_walker *walker)
{ {
if (!walker->stop) { if (!walker->stop) {
@ -439,8 +428,6 @@ static const struct Qdisc_class_ops tbf_class_ops =
.leaf = tbf_leaf, .leaf = tbf_leaf,
.get = tbf_get, .get = tbf_get,
.put = tbf_put, .put = tbf_put,
.change = tbf_change_class,
.delete = tbf_delete,
.walk = tbf_walk, .walk = tbf_walk,
.dump = tbf_dump_class, .dump = tbf_dump_class,
}; };