aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2010-05-14 04:08:14 -0400
committerDavid S. Miller <davem@davemloft.net>2010-05-17 20:44:46 -0400
commita2f79227138c71e08627af5f8961197364edbc98 (patch)
tree6d55f0769045bf537acd14db89b98fbe737ec595 /net/sched
parente1bc7eedbafe0415cdfd82e17e6f65bb3369239d (diff)
net_sched: sch_hfsc: fix classification loops
When attaching filters to a class pointing to a class higher up in the hierarchy, classification may enter an endless loop. Currently this is prevented for filters that are already resolved, but not for filters resolved at runtime. Only allow filters to point downwards in the hierarchy, similar to what CBQ does. Reported-by: Pawel Staszewski <pstaszewski@itcare.pl> Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sched')
-rw-r--r--net/sched/sch_hfsc.c6
1 files changed, 5 insertions, 1 deletions
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
index b38b39c60752..a435cf13cc27 100644
--- a/net/sched/sch_hfsc.c
+++ b/net/sched/sch_hfsc.c
@@ -1155,7 +1155,7 @@ static struct hfsc_class *
1155hfsc_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr) 1155hfsc_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
1156{ 1156{
1157 struct hfsc_sched *q = qdisc_priv(sch); 1157 struct hfsc_sched *q = qdisc_priv(sch);
1158 struct hfsc_class *cl; 1158 struct hfsc_class *head, *cl;
1159 struct tcf_result res; 1159 struct tcf_result res;
1160 struct tcf_proto *tcf; 1160 struct tcf_proto *tcf;
1161 int result; 1161 int result;
@@ -1166,6 +1166,7 @@ hfsc_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
1166 return cl; 1166 return cl;
1167 1167
1168 *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS; 1168 *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
1169 head = &q->root;
1169 tcf = q->root.filter_list; 1170 tcf = q->root.filter_list;
1170 while (tcf && (result = tc_classify(skb, tcf, &res)) >= 0) { 1171 while (tcf && (result = tc_classify(skb, tcf, &res)) >= 0) {
1171#ifdef CONFIG_NET_CLS_ACT 1172#ifdef CONFIG_NET_CLS_ACT
@@ -1180,6 +1181,8 @@ hfsc_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
1180 if ((cl = (struct hfsc_class *)res.class) == NULL) { 1181 if ((cl = (struct hfsc_class *)res.class) == NULL) {
1181 if ((cl = hfsc_find_class(res.classid, sch)) == NULL) 1182 if ((cl = hfsc_find_class(res.classid, sch)) == NULL)
1182 break; /* filter selected invalid classid */ 1183 break; /* filter selected invalid classid */
1184 if (cl->level >= head->level)
1185 break; /* filter may only point downwards */
1183 } 1186 }
1184 1187
1185 if (cl->level == 0) 1188 if (cl->level == 0)
@@ -1187,6 +1190,7 @@ hfsc_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
1187 1190
1188 /* apply inner filter chain */ 1191 /* apply inner filter chain */
1189 tcf = cl->filter_list; 1192 tcf = cl->filter_list;
1193 head = cl;
1190 } 1194 }
1191 1195
1192 /* classification failed, try default class */ 1196 /* classification failed, try default class */