Commit 0250c7f6 authored by Thomas Graf's avatar Thomas Graf Committed by David S. Miller

[PKT_SCHED]: CBQ; Destroy filters before destroying classes.

CBQ destroys its classes by traversing the hashtable and thus classes
are not destroyed from root to leafs which means that class Y being
a subclass of class X may be destroyed before X. This is a problem
if a filter is attached to class X (parent) classifying into class Y
(result). In case Y gets deleted before X the filter references an
already deleted class while trying to unbind (cbq_unbind_filter).
Therefore all filters must be destroyed before destroying classes. An
additional BUG_TRAP has been added to document this not so obvious case.

The BUG can be triggered with the following commands:
 qdisc add dev  root handle 10:0 cbq bandwidth 100Mbit avpkt 1400 mpu 64
 class add dev  parent 10:0  classid 10:12 cbq bandwidth 100mbit        rate 100mbit allot 1514 prio 3 maxburst 1 avpkt  500 bounded
 class add dev  parent 10:12  classid 10:13 cbq bandwidth 100mbit        rate 100mbit allot 1514 prio 3 maxburst 1 avpkt  500 bounded
 filter add dev  parent 10:12 protocol ip prio 10 u32 match ip protocol 6 0xff flowid 10:13
 qdisc del dev  root

The deletion ordering in the above case is: 10:0 -> 10:13 -> 10:12
Signed-off-by: default avatarThomas Graf <tgraf@suug.ch>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8156f706
...@@ -1749,6 +1749,8 @@ static void cbq_destroy_class(struct Qdisc *sch, struct cbq_class *cl) ...@@ -1749,6 +1749,8 @@ static void cbq_destroy_class(struct Qdisc *sch, struct cbq_class *cl)
{ {
struct cbq_sched_data *q = qdisc_priv(sch); struct cbq_sched_data *q = qdisc_priv(sch);
BUG_TRAP(!cl->filters);
cbq_destroy_filters(cl); cbq_destroy_filters(cl);
qdisc_destroy(cl->q); qdisc_destroy(cl->q);
qdisc_put_rtab(cl->R_tab); qdisc_put_rtab(cl->R_tab);
...@@ -1769,6 +1771,14 @@ cbq_destroy(struct Qdisc* sch) ...@@ -1769,6 +1771,14 @@ cbq_destroy(struct Qdisc* sch)
#ifdef CONFIG_NET_CLS_POLICE #ifdef CONFIG_NET_CLS_POLICE
q->rx_class = NULL; q->rx_class = NULL;
#endif #endif
/*
* Filters must be destroyed first because we don't destroy the
* classes from root to leafs which means that filters can still
* be bound to classes which have been destroyed already. --TGR '04
*/
for (h = 0; h < 16; h++)
for (cl = q->classes[h]; cl; cl = cl->next)
cbq_destroy_filters(cl);
for (h = 0; h < 16; h++) { for (h = 0; h < 16; h++) {
struct cbq_class *next; struct cbq_class *next;
......
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