Blame view
net/sched/sch_gred.c
13.8 KB
1da177e4c
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/* * net/sched/sch_gred.c Generic Random Early Detection queue. * * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * Authors: J Hadi Salim (hadi@cyberus.ca) 1998-2002 * * 991129: - Bug fix with grio mode * - a better sing. AvgQ mode with Grio(WRED) * - A finer grained VQ dequeue based on sugestion * from Ren Liu * - More error checks * |
1e4dfaf9b
|
18 |
* For all the glorious comments look at include/net/red.h |
1da177e4c
|
19 |
*/ |
5a0e3ad6a
|
20 |
#include <linux/slab.h> |
1da177e4c
|
21 |
#include <linux/module.h> |
1da177e4c
|
22 23 |
#include <linux/types.h> #include <linux/kernel.h> |
1da177e4c
|
24 |
#include <linux/skbuff.h> |
1da177e4c
|
25 |
#include <net/pkt_sched.h> |
22b33429a
|
26 |
#include <net/red.h> |
1da177e4c
|
27 |
|
f62d6b936
|
28 |
#define GRED_DEF_PRIO (MAX_DPs / 2) |
716a1b40b
|
29 |
#define GRED_VQ_MASK (MAX_DPs - 1) |
f62d6b936
|
30 |
|
1da177e4c
|
31 32 |
struct gred_sched_data; struct gred_sched; |
cc7ec456f
|
33 |
struct gred_sched_data { |
1da177e4c
|
34 |
u32 limit; /* HARD maximal queue length */ |
a73ed26bb
|
35 |
u32 DP; /* the drop parameters */ |
1da177e4c
|
36 37 38 |
u32 bytesin; /* bytes seen on virtualQ so far*/ u32 packetsin; /* packets seen on virtualQ so far*/ u32 backlog; /* bytes on the virtualQ */ |
1e4dfaf9b
|
39 |
u8 prio; /* the prio of this vq */ |
1da177e4c
|
40 |
|
22b33429a
|
41 |
struct red_parms parms; |
eeca6688d
|
42 |
struct red_vars vars; |
22b33429a
|
43 |
struct red_stats stats; |
1da177e4c
|
44 |
}; |
dea3f6285
|
45 46 |
enum { GRED_WRED_MODE = 1, |
d6fd4e966
|
47 |
GRED_RIO_MODE, |
dea3f6285
|
48 |
}; |
cc7ec456f
|
49 |
struct gred_sched { |
1da177e4c
|
50 |
struct gred_sched_data *tab[MAX_DPs]; |
dea3f6285
|
51 |
unsigned long flags; |
b38c7eef7
|
52 |
u32 red_flags; |
1e4dfaf9b
|
53 54 |
u32 DPs; u32 def; |
eeca6688d
|
55 |
struct red_vars wred_set; |
1da177e4c
|
56 |
}; |
dea3f6285
|
57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
static inline int gred_wred_mode(struct gred_sched *table) { return test_bit(GRED_WRED_MODE, &table->flags); } static inline void gred_enable_wred_mode(struct gred_sched *table) { __set_bit(GRED_WRED_MODE, &table->flags); } static inline void gred_disable_wred_mode(struct gred_sched *table) { __clear_bit(GRED_WRED_MODE, &table->flags); } |
d6fd4e966
|
71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
static inline int gred_rio_mode(struct gred_sched *table) { return test_bit(GRED_RIO_MODE, &table->flags); } static inline void gred_enable_rio_mode(struct gred_sched *table) { __set_bit(GRED_RIO_MODE, &table->flags); } static inline void gred_disable_rio_mode(struct gred_sched *table) { __clear_bit(GRED_RIO_MODE, &table->flags); } |
dea3f6285
|
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
static inline int gred_wred_mode_check(struct Qdisc *sch) { struct gred_sched *table = qdisc_priv(sch); int i; /* Really ugly O(n^2) but shouldn't be necessary too frequent. */ for (i = 0; i < table->DPs; i++) { struct gred_sched_data *q = table->tab[i]; int n; if (q == NULL) continue; for (n = 0; n < table->DPs; n++) if (table->tab[n] && table->tab[n] != q && table->tab[n]->prio == q->prio) return 1; } return 0; } |
22b33429a
|
106 107 108 109 110 111 112 113 114 |
static inline unsigned int gred_backlog(struct gred_sched *table, struct gred_sched_data *q, struct Qdisc *sch) { if (gred_wred_mode(table)) return sch->qstats.backlog; else return q->backlog; } |
716a1b40b
|
115 116 117 118 |
static inline u16 tc_index_to_dp(struct sk_buff *skb) { return skb->tc_index & GRED_VQ_MASK; } |
eeca6688d
|
119 |
static inline void gred_load_wred_set(const struct gred_sched *table, |
7051703b9
|
120 121 |
struct gred_sched_data *q) { |
eeca6688d
|
122 123 |
q->vars.qavg = table->wred_set.qavg; q->vars.qidlestart = table->wred_set.qidlestart; |
7051703b9
|
124 125 126 127 128 |
} static inline void gred_store_wred_set(struct gred_sched *table, struct gred_sched_data *q) { |
eeca6688d
|
129 |
table->wred_set.qavg = q->vars.qavg; |
7051703b9
|
130 |
} |
b38c7eef7
|
131 132 133 134 |
static inline int gred_use_ecn(struct gred_sched *t) { return t->red_flags & TC_RED_ECN; } |
bdc450a0b
|
135 136 137 138 |
static inline int gred_use_harddrop(struct gred_sched *t) { return t->red_flags & TC_RED_HARDDROP; } |
cc7ec456f
|
139 |
static int gred_enqueue(struct sk_buff *skb, struct Qdisc *sch) |
1da177e4c
|
140 |
{ |
cc7ec456f
|
141 142 |
struct gred_sched_data *q = NULL; struct gred_sched *t = qdisc_priv(sch); |
22b33429a
|
143 |
unsigned long qavg = 0; |
4a591834c
|
144 |
u16 dp = tc_index_to_dp(skb); |
1da177e4c
|
145 |
|
cc7ec456f
|
146 |
if (dp >= t->DPs || (q = t->tab[dp]) == NULL) { |
18e3fb84e
|
147 |
dp = t->def; |
cc7ec456f
|
148 149 |
q = t->tab[dp]; if (!q) { |
18e3fb84e
|
150 151 152 153 |
/* Pass through packets not assigned to a DP * if no default DP has been configured. This * allows for DP flows to be left untouched. */ |
5ce2d488f
|
154 |
if (skb_queue_len(&sch->q) < qdisc_dev(sch)->tx_queue_len) |
18e3fb84e
|
155 156 157 |
return qdisc_enqueue_tail(skb, sch); else goto drop; |
1da177e4c
|
158 |
} |
18e3fb84e
|
159 |
|
eeca6688d
|
160 |
/* fix tc_index? --could be controversial but needed for |
1da177e4c
|
161 |
requeueing */ |
18e3fb84e
|
162 |
skb->tc_index = (skb->tc_index & ~GRED_VQ_MASK) | dp; |
1da177e4c
|
163 |
} |
1e4dfaf9b
|
164 |
/* sum up all the qaves of prios <= to ours to get the new qave */ |
d6fd4e966
|
165 |
if (!gred_wred_mode(t) && gred_rio_mode(t)) { |
1e4dfaf9b
|
166 167 168 169 |
int i; for (i = 0; i < t->DPs; i++) { if (t->tab[i] && t->tab[i]->prio < q->prio && |
eeca6688d
|
170 171 |
!red_is_idling(&t->tab[i]->vars)) qavg += t->tab[i]->vars.qavg; |
1da177e4c
|
172 |
} |
1e4dfaf9b
|
173 |
|
1da177e4c
|
174 175 176 |
} q->packetsin++; |
0abf77e55
|
177 |
q->bytesin += qdisc_pkt_len(skb); |
1da177e4c
|
178 |
|
1e4dfaf9b
|
179 |
if (gred_wred_mode(t)) |
7051703b9
|
180 |
gred_load_wred_set(t, q); |
1da177e4c
|
181 |
|
eeca6688d
|
182 183 184 |
q->vars.qavg = red_calc_qavg(&q->parms, &q->vars, gred_backlog(t, q, sch)); |
1da177e4c
|
185 |
|
eeca6688d
|
186 187 |
if (red_is_idling(&q->vars)) red_end_of_idle_period(&q->vars); |
1da177e4c
|
188 |
|
dea3f6285
|
189 |
if (gred_wred_mode(t)) |
7051703b9
|
190 |
gred_store_wred_set(t, q); |
1da177e4c
|
191 |
|
eeca6688d
|
192 |
switch (red_action(&q->parms, &q->vars, q->vars.qavg + qavg)) { |
cc7ec456f
|
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
case RED_DONT_MARK: break; case RED_PROB_MARK: sch->qstats.overlimits++; if (!gred_use_ecn(t) || !INET_ECN_set_ce(skb)) { q->stats.prob_drop++; goto congestion_drop; } q->stats.prob_mark++; break; case RED_HARD_MARK: sch->qstats.overlimits++; if (gred_use_harddrop(t) || !gred_use_ecn(t) || !INET_ECN_set_ce(skb)) { q->stats.forced_drop++; goto congestion_drop; } q->stats.forced_mark++; break; |
1da177e4c
|
215 |
} |
22b33429a
|
216 |
|
0abf77e55
|
217 218 |
if (q->backlog + qdisc_pkt_len(skb) <= q->limit) { q->backlog += qdisc_pkt_len(skb); |
edf7a7b1f
|
219 |
return qdisc_enqueue_tail(skb, sch); |
1da177e4c
|
220 |
} |
22b33429a
|
221 222 223 |
q->stats.pdrop++; drop: |
edf7a7b1f
|
224 |
return qdisc_drop(skb, sch); |
c3b553cda
|
225 226 |
congestion_drop: |
edf7a7b1f
|
227 |
qdisc_drop(skb, sch); |
c3b553cda
|
228 |
return NET_XMIT_CN; |
1da177e4c
|
229 |
} |
cc7ec456f
|
230 |
static struct sk_buff *gred_dequeue(struct Qdisc *sch) |
1da177e4c
|
231 232 |
{ struct sk_buff *skb; |
1e4dfaf9b
|
233 |
struct gred_sched *t = qdisc_priv(sch); |
1da177e4c
|
234 |
|
edf7a7b1f
|
235 |
skb = qdisc_dequeue_head(sch); |
1da177e4c
|
236 |
if (skb) { |
1e4dfaf9b
|
237 |
struct gred_sched_data *q; |
18e3fb84e
|
238 239 240 241 |
u16 dp = tc_index_to_dp(skb); if (dp >= t->DPs || (q = t->tab[dp]) == NULL) { if (net_ratelimit()) |
cc7ec456f
|
242 243 244 245 |
pr_warning("GRED: Unable to relocate VQ 0x%x " "after dequeue, screwing up " "backlog. ", tc_index_to_dp(skb)); |
18e3fb84e
|
246 |
} else { |
0abf77e55
|
247 |
q->backlog -= qdisc_pkt_len(skb); |
18e3fb84e
|
248 |
|
dea3f6285
|
249 |
if (!q->backlog && !gred_wred_mode(t)) |
eeca6688d
|
250 |
red_start_of_idle_period(&q->vars); |
1da177e4c
|
251 |
} |
18e3fb84e
|
252 |
|
1da177e4c
|
253 254 |
return skb; } |
d8f64e196
|
255 |
if (gred_wred_mode(t) && !red_is_idling(&t->wred_set)) |
7051703b9
|
256 |
red_start_of_idle_period(&t->wred_set); |
1da177e4c
|
257 258 259 |
return NULL; } |
cc7ec456f
|
260 |
static unsigned int gred_drop(struct Qdisc *sch) |
1da177e4c
|
261 262 |
{ struct sk_buff *skb; |
1e4dfaf9b
|
263 |
struct gred_sched *t = qdisc_priv(sch); |
1da177e4c
|
264 |
|
edf7a7b1f
|
265 |
skb = qdisc_dequeue_tail(sch); |
1da177e4c
|
266 |
if (skb) { |
0abf77e55
|
267 |
unsigned int len = qdisc_pkt_len(skb); |
1e4dfaf9b
|
268 |
struct gred_sched_data *q; |
18e3fb84e
|
269 270 271 272 |
u16 dp = tc_index_to_dp(skb); if (dp >= t->DPs || (q = t->tab[dp]) == NULL) { if (net_ratelimit()) |
cc7ec456f
|
273 274 275 276 |
pr_warning("GRED: Unable to relocate VQ 0x%x " "while dropping, screwing up " "backlog. ", tc_index_to_dp(skb)); |
18e3fb84e
|
277 |
} else { |
1da177e4c
|
278 |
q->backlog -= len; |
22b33429a
|
279 |
q->stats.other++; |
18e3fb84e
|
280 |
|
dea3f6285
|
281 |
if (!q->backlog && !gred_wred_mode(t)) |
eeca6688d
|
282 |
red_start_of_idle_period(&q->vars); |
1da177e4c
|
283 |
} |
edf7a7b1f
|
284 |
qdisc_drop(skb, sch); |
1da177e4c
|
285 286 |
return len; } |
d8f64e196
|
287 |
if (gred_wred_mode(t) && !red_is_idling(&t->wred_set)) |
7051703b9
|
288 |
red_start_of_idle_period(&t->wred_set); |
1da177e4c
|
289 |
|
1da177e4c
|
290 291 292 |
return 0; } |
cc7ec456f
|
293 |
static void gred_reset(struct Qdisc *sch) |
1da177e4c
|
294 295 |
{ int i; |
1e4dfaf9b
|
296 |
struct gred_sched *t = qdisc_priv(sch); |
1da177e4c
|
297 |
|
edf7a7b1f
|
298 |
qdisc_reset_queue(sch); |
1da177e4c
|
299 |
|
10297b993
|
300 |
for (i = 0; i < t->DPs; i++) { |
1e4dfaf9b
|
301 302 303 304 |
struct gred_sched_data *q = t->tab[i]; if (!q) continue; |
eeca6688d
|
305 |
red_restart(&q->vars); |
1da177e4c
|
306 |
q->backlog = 0; |
1da177e4c
|
307 308 |
} } |
6639607ed
|
309 310 311 312 |
static inline void gred_destroy_vq(struct gred_sched_data *q) { kfree(q); } |
1e90474c3
|
313 |
static inline int gred_change_table_def(struct Qdisc *sch, struct nlattr *dps) |
1da177e4c
|
314 315 |
{ struct gred_sched *table = qdisc_priv(sch); |
1da177e4c
|
316 |
struct tc_gred_sopt *sopt; |
6639607ed
|
317 |
int i; |
1da177e4c
|
318 |
|
27a3421e4
|
319 |
if (dps == NULL) |
1da177e4c
|
320 |
return -EINVAL; |
1e90474c3
|
321 |
sopt = nla_data(dps); |
1da177e4c
|
322 |
|
6639607ed
|
323 324 |
if (sopt->DPs > MAX_DPs || sopt->DPs == 0 || sopt->def_DP >= sopt->DPs) return -EINVAL; |
1da177e4c
|
325 |
|
6639607ed
|
326 327 328 |
sch_tree_lock(sch); table->DPs = sopt->DPs; table->def = sopt->def_DP; |
b38c7eef7
|
329 |
table->red_flags = sopt->flags; |
dea3f6285
|
330 |
|
6639607ed
|
331 332 333 334 335 336 |
/* * Every entry point to GRED is synchronized with the above code * and the DP is checked against DPs, i.e. shadowed VQs can no * longer be found so we can unlock right here. */ sch_tree_unlock(sch); |
dea3f6285
|
337 |
|
6639607ed
|
338 339 340 341 342 343 344 345 346 347 348 349 |
if (sopt->grio) { gred_enable_rio_mode(table); gred_disable_wred_mode(table); if (gred_wred_mode_check(sch)) gred_enable_wred_mode(table); } else { gred_disable_rio_mode(table); gred_disable_wred_mode(table); } for (i = table->DPs; i < MAX_DPs; i++) { if (table->tab[i]) { |
cc7ec456f
|
350 351 352 |
pr_warning("GRED: Warning: Destroying " "shadowed VQ 0x%x ", i); |
6639607ed
|
353 354 |
gred_destroy_vq(table->tab[i]); table->tab[i] = NULL; |
10297b993
|
355 |
} |
6639607ed
|
356 |
} |
1da177e4c
|
357 |
|
6639607ed
|
358 359 |
return 0; } |
f62d6b936
|
360 |
static inline int gred_change_vq(struct Qdisc *sch, int dp, |
a73ed26bb
|
361 |
struct tc_gred_qopt *ctl, int prio, |
869aa4104
|
362 363 |
u8 *stab, u32 max_P, struct gred_sched_data **prealloc) |
6639607ed
|
364 365 |
{ struct gred_sched *table = qdisc_priv(sch); |
869aa4104
|
366 |
struct gred_sched_data *q = table->tab[dp]; |
f62d6b936
|
367 |
|
869aa4104
|
368 369 370 371 |
if (!q) { table->tab[dp] = q = *prealloc; *prealloc = NULL; if (!q) |
f62d6b936
|
372 |
return -ENOMEM; |
f62d6b936
|
373 |
} |
f62d6b936
|
374 375 |
q->DP = dp; q->prio = prio; |
f62d6b936
|
376 |
q->limit = ctl->limit; |
22b33429a
|
377 378 |
if (q->backlog == 0) |
eeca6688d
|
379 |
red_end_of_idle_period(&q->vars); |
22b33429a
|
380 381 382 |
red_set_parms(&q->parms, ctl->qth_min, ctl->qth_max, ctl->Wlog, ctl->Plog, |
a73ed26bb
|
383 |
ctl->Scell_log, stab, max_P); |
eeca6688d
|
384 |
red_set_vars(&q->vars); |
f62d6b936
|
385 386 |
return 0; } |
27a3421e4
|
387 388 389 390 |
static const struct nla_policy gred_policy[TCA_GRED_MAX + 1] = { [TCA_GRED_PARMS] = { .len = sizeof(struct tc_gred_qopt) }, [TCA_GRED_STAB] = { .len = 256 }, [TCA_GRED_DPS] = { .len = sizeof(struct tc_gred_sopt) }, |
a73ed26bb
|
391 |
[TCA_GRED_MAX_P] = { .type = NLA_U32 }, |
27a3421e4
|
392 |
}; |
1e90474c3
|
393 |
static int gred_change(struct Qdisc *sch, struct nlattr *opt) |
f62d6b936
|
394 395 |
{ struct gred_sched *table = qdisc_priv(sch); |
6639607ed
|
396 |
struct tc_gred_qopt *ctl; |
1e90474c3
|
397 |
struct nlattr *tb[TCA_GRED_MAX + 1]; |
cee63723b
|
398 |
int err, prio = GRED_DEF_PRIO; |
f62d6b936
|
399 |
u8 *stab; |
a73ed26bb
|
400 |
u32 max_P; |
869aa4104
|
401 |
struct gred_sched_data *prealloc; |
6639607ed
|
402 |
|
cee63723b
|
403 |
if (opt == NULL) |
6639607ed
|
404 |
return -EINVAL; |
27a3421e4
|
405 |
err = nla_parse_nested(tb, TCA_GRED_MAX, opt, gred_policy); |
cee63723b
|
406 407 |
if (err < 0) return err; |
1e90474c3
|
408 |
if (tb[TCA_GRED_PARMS] == NULL && tb[TCA_GRED_STAB] == NULL) |
f62d6b936
|
409 |
return gred_change_table_def(sch, opt); |
1da177e4c
|
410 |
|
1e90474c3
|
411 |
if (tb[TCA_GRED_PARMS] == NULL || |
27a3421e4
|
412 |
tb[TCA_GRED_STAB] == NULL) |
f62d6b936
|
413 |
return -EINVAL; |
1da177e4c
|
414 |
|
a73ed26bb
|
415 |
max_P = tb[TCA_GRED_MAX_P] ? nla_get_u32(tb[TCA_GRED_MAX_P]) : 0; |
cee63723b
|
416 |
err = -EINVAL; |
1e90474c3
|
417 418 |
ctl = nla_data(tb[TCA_GRED_PARMS]); stab = nla_data(tb[TCA_GRED_STAB]); |
a8aaa9958
|
419 420 |
if (ctl->DP >= table->DPs) |
f62d6b936
|
421 |
goto errout; |
1da177e4c
|
422 |
|
d6fd4e966
|
423 |
if (gred_rio_mode(table)) { |
f62d6b936
|
424 425 426 427 428 429 430 431 432 433 434 435 436 |
if (ctl->prio == 0) { int def_prio = GRED_DEF_PRIO; if (table->tab[table->def]) def_prio = table->tab[table->def]->prio; printk(KERN_DEBUG "GRED: DP %u does not have a prio " "setting default to %d ", ctl->DP, def_prio); prio = def_prio; } else prio = ctl->prio; |
1da177e4c
|
437 |
} |
869aa4104
|
438 |
prealloc = kzalloc(sizeof(*prealloc), GFP_KERNEL); |
f62d6b936
|
439 |
sch_tree_lock(sch); |
1da177e4c
|
440 |
|
869aa4104
|
441 |
err = gred_change_vq(sch, ctl->DP, ctl, prio, stab, max_P, &prealloc); |
f62d6b936
|
442 443 |
if (err < 0) goto errout_locked; |
1da177e4c
|
444 |
|
d6fd4e966
|
445 |
if (gred_rio_mode(table)) { |
dea3f6285
|
446 447 448 |
gred_disable_wred_mode(table); if (gred_wred_mode_check(sch)) gred_enable_wred_mode(table); |
1da177e4c
|
449 |
} |
f62d6b936
|
450 |
err = 0; |
1da177e4c
|
451 |
|
f62d6b936
|
452 453 |
errout_locked: sch_tree_unlock(sch); |
869aa4104
|
454 |
kfree(prealloc); |
f62d6b936
|
455 456 |
errout: return err; |
1da177e4c
|
457 |
} |
1e90474c3
|
458 |
static int gred_init(struct Qdisc *sch, struct nlattr *opt) |
1da177e4c
|
459 |
{ |
1e90474c3
|
460 |
struct nlattr *tb[TCA_GRED_MAX + 1]; |
cee63723b
|
461 |
int err; |
1da177e4c
|
462 |
|
cee63723b
|
463 |
if (opt == NULL) |
1da177e4c
|
464 |
return -EINVAL; |
27a3421e4
|
465 |
err = nla_parse_nested(tb, TCA_GRED_MAX, opt, gred_policy); |
cee63723b
|
466 467 |
if (err < 0) return err; |
1e90474c3
|
468 |
if (tb[TCA_GRED_PARMS] || tb[TCA_GRED_STAB]) |
6639607ed
|
469 |
return -EINVAL; |
1da177e4c
|
470 |
|
1e90474c3
|
471 |
return gred_change_table_def(sch, tb[TCA_GRED_DPS]); |
1da177e4c
|
472 473 474 475 |
} static int gred_dump(struct Qdisc *sch, struct sk_buff *skb) { |
1da177e4c
|
476 |
struct gred_sched *table = qdisc_priv(sch); |
1e90474c3
|
477 |
struct nlattr *parms, *opts = NULL; |
1da177e4c
|
478 |
int i; |
a73ed26bb
|
479 |
u32 max_p[MAX_DPs]; |
e06368221
|
480 481 482 483 |
struct tc_gred_sopt sopt = { .DPs = table->DPs, .def_DP = table->def, .grio = gred_rio_mode(table), |
b38c7eef7
|
484 |
.flags = table->red_flags, |
e06368221
|
485 |
}; |
1da177e4c
|
486 |
|
1e90474c3
|
487 488 489 490 |
opts = nla_nest_start(skb, TCA_OPTIONS); if (opts == NULL) goto nla_put_failure; NLA_PUT(skb, TCA_GRED_DPS, sizeof(sopt), &sopt); |
a73ed26bb
|
491 492 493 494 495 496 497 |
for (i = 0; i < MAX_DPs; i++) { struct gred_sched_data *q = table->tab[i]; max_p[i] = q ? q->parms.max_P : 0; } NLA_PUT(skb, TCA_GRED_MAX_P, sizeof(max_p), max_p); |
1e90474c3
|
498 499 500 |
parms = nla_nest_start(skb, TCA_GRED_PARMS); if (parms == NULL) goto nla_put_failure; |
1da177e4c
|
501 |
|
05f1cc01b
|
502 503 504 |
for (i = 0; i < MAX_DPs; i++) { struct gred_sched_data *q = table->tab[i]; struct tc_gred_qopt opt; |
1da177e4c
|
505 |
|
05f1cc01b
|
506 |
memset(&opt, 0, sizeof(opt)); |
1da177e4c
|
507 508 509 510 511 |
if (!q) { /* hack -- fix at some point with proper message This is how we indicate to tc that there is no VQ at this DP */ |
05f1cc01b
|
512 513 |
opt.DP = MAX_DPs + i; goto append_opt; |
1da177e4c
|
514 |
} |
05f1cc01b
|
515 516 517 518 |
opt.limit = q->limit; opt.DP = q->DP; opt.backlog = q->backlog; opt.prio = q->prio; |
22b33429a
|
519 520 521 522 523 524 525 526 527 |
opt.qth_min = q->parms.qth_min >> q->parms.Wlog; opt.qth_max = q->parms.qth_max >> q->parms.Wlog; opt.Wlog = q->parms.Wlog; opt.Plog = q->parms.Plog; opt.Scell_log = q->parms.Scell_log; opt.other = q->stats.other; opt.early = q->stats.prob_drop; opt.forced = q->stats.forced_drop; opt.pdrop = q->stats.pdrop; |
05f1cc01b
|
528 529 |
opt.packets = q->packetsin; opt.bytesin = q->bytesin; |
22b33429a
|
530 |
if (gred_wred_mode(table)) { |
eeca6688d
|
531 532 533 |
q->vars.qidlestart = table->tab[table->def]->vars.qidlestart; q->vars.qavg = table->tab[table->def]->vars.qavg; |
1da177e4c
|
534 |
} |
05f1cc01b
|
535 |
|
eeca6688d
|
536 |
opt.qave = red_calc_qavg(&q->parms, &q->vars, q->vars.qavg); |
22b33429a
|
537 |
|
05f1cc01b
|
538 |
append_opt: |
1e90474c3
|
539 540 |
if (nla_append(skb, sizeof(opt), &opt) < 0) goto nla_put_failure; |
1da177e4c
|
541 |
} |
1e90474c3
|
542 |
nla_nest_end(skb, parms); |
1da177e4c
|
543 |
|
1e90474c3
|
544 |
return nla_nest_end(skb, opts); |
1da177e4c
|
545 |
|
1e90474c3
|
546 |
nla_put_failure: |
bc3ed28ca
|
547 548 |
nla_nest_cancel(skb, opts); return -EMSGSIZE; |
1da177e4c
|
549 550 551 552 553 554 |
} static void gred_destroy(struct Qdisc *sch) { struct gred_sched *table = qdisc_priv(sch); int i; |
1e4dfaf9b
|
555 |
for (i = 0; i < table->DPs; i++) { |
1da177e4c
|
556 |
if (table->tab[i]) |
6639607ed
|
557 |
gred_destroy_vq(table->tab[i]); |
1da177e4c
|
558 559 |
} } |
20fea08b5
|
560 |
static struct Qdisc_ops gred_qdisc_ops __read_mostly = { |
1da177e4c
|
561 562 563 564 |
.id = "gred", .priv_size = sizeof(struct gred_sched), .enqueue = gred_enqueue, .dequeue = gred_dequeue, |
8e3af9789
|
565 |
.peek = qdisc_peek_head, |
1da177e4c
|
566 567 568 569 570 571 572 573 574 575 576 577 578 |
.drop = gred_drop, .init = gred_init, .reset = gred_reset, .destroy = gred_destroy, .change = gred_change, .dump = gred_dump, .owner = THIS_MODULE, }; static int __init gred_module_init(void) { return register_qdisc(&gred_qdisc_ops); } |
1e4dfaf9b
|
579 580 |
static void __exit gred_module_exit(void) |
1da177e4c
|
581 582 583 |
{ unregister_qdisc(&gred_qdisc_ops); } |
1e4dfaf9b
|
584 |
|
1da177e4c
|
585 586 |
module_init(gred_module_init) module_exit(gred_module_exit) |
1e4dfaf9b
|
587 |
|
1da177e4c
|
588 |
MODULE_LICENSE("GPL"); |