aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/sch_gred.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched/sch_gred.c')
-rw-r--r--net/sched/sch_gred.c87
1 files changed, 65 insertions, 22 deletions
diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c
index 25c171c32715..4ced47bf6089 100644
--- a/net/sched/sch_gred.c
+++ b/net/sched/sch_gred.c
@@ -91,16 +91,57 @@ struct gred_sched_data
91 psched_time_t qidlestart; /* Start of idle period */ 91 psched_time_t qidlestart; /* Start of idle period */
92}; 92};
93 93
94enum {
95 GRED_WRED_MODE = 1,
96};
97
94struct gred_sched 98struct gred_sched
95{ 99{
96 struct gred_sched_data *tab[MAX_DPs]; 100 struct gred_sched_data *tab[MAX_DPs];
101 unsigned long flags;
97 u32 DPs; 102 u32 DPs;
98 u32 def; 103 u32 def;
99 u8 initd; 104 u8 initd;
100 u8 grio; 105 u8 grio;
101 u8 eqp;
102}; 106};
103 107
108static inline int gred_wred_mode(struct gred_sched *table)
109{
110 return test_bit(GRED_WRED_MODE, &table->flags);
111}
112
113static inline void gred_enable_wred_mode(struct gred_sched *table)
114{
115 __set_bit(GRED_WRED_MODE, &table->flags);
116}
117
118static inline void gred_disable_wred_mode(struct gred_sched *table)
119{
120 __clear_bit(GRED_WRED_MODE, &table->flags);
121}
122
123static inline int gred_wred_mode_check(struct Qdisc *sch)
124{
125 struct gred_sched *table = qdisc_priv(sch);
126 int i;
127
128 /* Really ugly O(n^2) but shouldn't be necessary too frequent. */
129 for (i = 0; i < table->DPs; i++) {
130 struct gred_sched_data *q = table->tab[i];
131 int n;
132
133 if (q == NULL)
134 continue;
135
136 for (n = 0; n < table->DPs; n++)
137 if (table->tab[n] && table->tab[n] != q &&
138 table->tab[n]->prio == q->prio)
139 return 1;
140 }
141
142 return 0;
143}
144
104static int 145static int
105gred_enqueue(struct sk_buff *skb, struct Qdisc* sch) 146gred_enqueue(struct sk_buff *skb, struct Qdisc* sch)
106{ 147{
@@ -132,7 +173,7 @@ gred_enqueue(struct sk_buff *skb, struct Qdisc* sch)
132 "general backlog %d\n",skb->tc_index&0xf,sch->handle,q->backlog, 173 "general backlog %d\n",skb->tc_index&0xf,sch->handle,q->backlog,
133 sch->qstats.backlog); 174 sch->qstats.backlog);
134 /* sum up all the qaves of prios <= to ours to get the new qave*/ 175 /* sum up all the qaves of prios <= to ours to get the new qave*/
135 if (!t->eqp && t->grio) { 176 if (!gred_wred_mode(t) && t->grio) {
136 for (i=0;i<t->DPs;i++) { 177 for (i=0;i<t->DPs;i++) {
137 if ((!t->tab[i]) || (i==q->DP)) 178 if ((!t->tab[i]) || (i==q->DP))
138 continue; 179 continue;
@@ -146,7 +187,7 @@ gred_enqueue(struct sk_buff *skb, struct Qdisc* sch)
146 q->packetsin++; 187 q->packetsin++;
147 q->bytesin+=skb->len; 188 q->bytesin+=skb->len;
148 189
149 if (t->eqp && t->grio) { 190 if (gred_wred_mode(t)) {
150 qave=0; 191 qave=0;
151 q->qave=t->tab[t->def]->qave; 192 q->qave=t->tab[t->def]->qave;
152 q->qidlestart=t->tab[t->def]->qidlestart; 193 q->qidlestart=t->tab[t->def]->qidlestart;
@@ -160,7 +201,7 @@ gred_enqueue(struct sk_buff *skb, struct Qdisc* sch)
160 201
161 q->qave >>= q->Stab[(us_idle>>q->Scell_log)&0xFF]; 202 q->qave >>= q->Stab[(us_idle>>q->Scell_log)&0xFF];
162 } else { 203 } else {
163 if (t->eqp) { 204 if (gred_wred_mode(t)) {
164 q->qave += sch->qstats.backlog - (q->qave >> q->Wlog); 205 q->qave += sch->qstats.backlog - (q->qave >> q->Wlog);
165 } else { 206 } else {
166 q->qave += q->backlog - (q->qave >> q->Wlog); 207 q->qave += q->backlog - (q->qave >> q->Wlog);
@@ -169,7 +210,7 @@ gred_enqueue(struct sk_buff *skb, struct Qdisc* sch)
169 } 210 }
170 211
171 212
172 if (t->eqp && t->grio) 213 if (gred_wred_mode(t))
173 t->tab[t->def]->qave=q->qave; 214 t->tab[t->def]->qave=q->qave;
174 215
175 if ((q->qave+qave) < q->qth_min) { 216 if ((q->qave+qave) < q->qth_min) {
@@ -240,7 +281,7 @@ gred_dequeue(struct Qdisc* sch)
240 q= t->tab[(skb->tc_index&0xf)]; 281 q= t->tab[(skb->tc_index&0xf)];
241 if (q) { 282 if (q) {
242 q->backlog -= skb->len; 283 q->backlog -= skb->len;
243 if (!q->backlog && !t->eqp) 284 if (!q->backlog && !gred_wred_mode(t))
244 PSCHED_GET_TIME(q->qidlestart); 285 PSCHED_GET_TIME(q->qidlestart);
245 } else { 286 } else {
246 D2PRINTK("gred_dequeue: skb has bad tcindex %x\n",skb->tc_index&0xf); 287 D2PRINTK("gred_dequeue: skb has bad tcindex %x\n",skb->tc_index&0xf);
@@ -248,7 +289,7 @@ gred_dequeue(struct Qdisc* sch)
248 return skb; 289 return skb;
249 } 290 }
250 291
251 if (t->eqp) { 292 if (gred_wred_mode(t)) {
252 q= t->tab[t->def]; 293 q= t->tab[t->def];
253 if (!q) 294 if (!q)
254 D2PRINTK("no default VQ set: Results will be " 295 D2PRINTK("no default VQ set: Results will be "
@@ -276,7 +317,7 @@ static unsigned int gred_drop(struct Qdisc* sch)
276 if (q) { 317 if (q) {
277 q->backlog -= len; 318 q->backlog -= len;
278 q->other++; 319 q->other++;
279 if (!q->backlog && !t->eqp) 320 if (!q->backlog && !gred_wred_mode(t))
280 PSCHED_GET_TIME(q->qidlestart); 321 PSCHED_GET_TIME(q->qidlestart);
281 } else { 322 } else {
282 D2PRINTK("gred_dequeue: skb has bad tcindex %x\n",skb->tc_index&0xf); 323 D2PRINTK("gred_dequeue: skb has bad tcindex %x\n",skb->tc_index&0xf);
@@ -330,7 +371,6 @@ static int gred_change(struct Qdisc *sch, struct rtattr *opt)
330 struct tc_gred_sopt *sopt; 371 struct tc_gred_sopt *sopt;
331 struct rtattr *tb[TCA_GRED_STAB]; 372 struct rtattr *tb[TCA_GRED_STAB];
332 struct rtattr *tb2[TCA_GRED_DPS]; 373 struct rtattr *tb2[TCA_GRED_DPS];
333 int i;
334 374
335 if (opt == NULL || rtattr_parse_nested(tb, TCA_GRED_STAB, opt)) 375 if (opt == NULL || rtattr_parse_nested(tb, TCA_GRED_STAB, opt))
336 return -EINVAL; 376 return -EINVAL;
@@ -344,7 +384,17 @@ static int gred_change(struct Qdisc *sch, struct rtattr *opt)
344 sopt = RTA_DATA(tb2[TCA_GRED_DPS-1]); 384 sopt = RTA_DATA(tb2[TCA_GRED_DPS-1]);
345 table->DPs=sopt->DPs; 385 table->DPs=sopt->DPs;
346 table->def=sopt->def_DP; 386 table->def=sopt->def_DP;
347 table->grio=sopt->grio; 387
388 if (sopt->grio) {
389 table->grio = 1;
390 gred_disable_wred_mode(table);
391 if (gred_wred_mode_check(sch))
392 gred_enable_wred_mode(table);
393 } else {
394 table->grio = 0;
395 gred_disable_wred_mode(table);
396 }
397
348 table->initd=0; 398 table->initd=0;
349 /* probably need to clear all the table DP entries as well */ 399 /* probably need to clear all the table DP entries as well */
350 return 0; 400 return 0;
@@ -413,17 +463,10 @@ static int gred_change(struct Qdisc *sch, struct rtattr *opt)
413 PSCHED_SET_PASTPERFECT(q->qidlestart); 463 PSCHED_SET_PASTPERFECT(q->qidlestart);
414 memcpy(q->Stab, RTA_DATA(tb[TCA_GRED_STAB-1]), 256); 464 memcpy(q->Stab, RTA_DATA(tb[TCA_GRED_STAB-1]), 256);
415 465
416 if ( table->initd && table->grio) { 466 if (table->grio) {
417 /* this looks ugly but it's not in the fast path */ 467 gred_disable_wred_mode(table);
418 for (i=0;i<table->DPs;i++) { 468 if (gred_wred_mode_check(sch))
419 if ((!table->tab[i]) || (i==q->DP) ) 469 gred_enable_wred_mode(table);
420 continue;
421 if (table->tab[i]->prio == q->prio ){
422 /* WRED mode detected */
423 table->eqp=1;
424 break;
425 }
426 }
427 } 470 }
428 471
429 if (!table->initd) { 472 if (!table->initd) {
@@ -541,7 +584,7 @@ static int gred_dump(struct Qdisc *sch, struct sk_buff *skb)
541 dst->DP=q->DP; 584 dst->DP=q->DP;
542 dst->backlog=q->backlog; 585 dst->backlog=q->backlog;
543 if (q->qave) { 586 if (q->qave) {
544 if (table->eqp && table->grio) { 587 if (gred_wred_mode(table)) {
545 q->qidlestart=table->tab[table->def]->qidlestart; 588 q->qidlestart=table->tab[table->def]->qidlestart;
546 q->qave=table->tab[table->def]->qave; 589 q->qave=table->tab[table->def]->qave;
547 } 590 }