Blame view
net/sched/sch_gred.c
13.7 KB
1da177e4c Linux-2.6.12-rc2 |
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 [PKT_SCHED]: GRED... |
18 |
* For all the glorious comments look at include/net/red.h |
1da177e4c Linux-2.6.12-rc2 |
19 |
*/ |
5a0e3ad6a include cleanup: ... |
20 |
#include <linux/slab.h> |
1da177e4c Linux-2.6.12-rc2 |
21 |
#include <linux/module.h> |
1da177e4c Linux-2.6.12-rc2 |
22 23 |
#include <linux/types.h> #include <linux/kernel.h> |
1da177e4c Linux-2.6.12-rc2 |
24 |
#include <linux/skbuff.h> |
1da177e4c Linux-2.6.12-rc2 |
25 |
#include <net/pkt_sched.h> |
22b33429a [PKT_SCHED]: GRED... |
26 |
#include <net/red.h> |
1da177e4c Linux-2.6.12-rc2 |
27 |
|
f62d6b936 [PKT_SCHED]: GRED... |
28 |
#define GRED_DEF_PRIO (MAX_DPs / 2) |
716a1b40b [PKT_SCHED]: GRED... |
29 |
#define GRED_VQ_MASK (MAX_DPs - 1) |
f62d6b936 [PKT_SCHED]: GRED... |
30 |
|
1da177e4c Linux-2.6.12-rc2 |
31 32 |
struct gred_sched_data; struct gred_sched; |
cc7ec456f net_sched: cleanups |
33 |
struct gred_sched_data { |
1da177e4c Linux-2.6.12-rc2 |
34 |
u32 limit; /* HARD maximal queue length */ |
a73ed26bb sch_red: generali... |
35 |
u32 DP; /* the drop parameters */ |
1da177e4c Linux-2.6.12-rc2 |
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 [PKT_SCHED]: GRED... |
39 |
u8 prio; /* the prio of this vq */ |
1da177e4c Linux-2.6.12-rc2 |
40 |
|
22b33429a [PKT_SCHED]: GRED... |
41 |
struct red_parms parms; |
eeca6688d net_sched: red: s... |
42 |
struct red_vars vars; |
22b33429a [PKT_SCHED]: GRED... |
43 |
struct red_stats stats; |
1da177e4c Linux-2.6.12-rc2 |
44 |
}; |
dea3f6285 [PKT_SCHED]: GRED... |
45 46 |
enum { GRED_WRED_MODE = 1, |
d6fd4e966 [PKT_SCHED]: GRED... |
47 |
GRED_RIO_MODE, |
dea3f6285 [PKT_SCHED]: GRED... |
48 |
}; |
cc7ec456f net_sched: cleanups |
49 |
struct gred_sched { |
1da177e4c Linux-2.6.12-rc2 |
50 |
struct gred_sched_data *tab[MAX_DPs]; |
dea3f6285 [PKT_SCHED]: GRED... |
51 |
unsigned long flags; |
b38c7eef7 [PKT_SCHED]: GRED... |
52 |
u32 red_flags; |
1e4dfaf9b [PKT_SCHED]: GRED... |
53 54 |
u32 DPs; u32 def; |
eeca6688d net_sched: red: s... |
55 |
struct red_vars wred_set; |
1da177e4c Linux-2.6.12-rc2 |
56 |
}; |
dea3f6285 [PKT_SCHED]: GRED... |
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 [PKT_SCHED]: GRED... |
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 [PKT_SCHED]: GRED... |
85 86 87 88 89 90 91 92 93 94 95 96 |
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; |
c22e46402 net_sched: gred: ... |
97 98 |
for (n = i + 1; n < table->DPs; n++) if (table->tab[n] && table->tab[n]->prio == q->prio) |
dea3f6285 [PKT_SCHED]: GRED... |
99 100 101 102 103 |
return 1; } return 0; } |
22b33429a [PKT_SCHED]: GRED... |
104 105 106 107 108 109 110 111 112 |
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 [PKT_SCHED]: GRED... |
113 114 115 116 |
static inline u16 tc_index_to_dp(struct sk_buff *skb) { return skb->tc_index & GRED_VQ_MASK; } |
eeca6688d net_sched: red: s... |
117 |
static inline void gred_load_wred_set(const struct gred_sched *table, |
7051703b9 [PKT_SCHED]: GRED... |
118 119 |
struct gred_sched_data *q) { |
eeca6688d net_sched: red: s... |
120 121 |
q->vars.qavg = table->wred_set.qavg; q->vars.qidlestart = table->wred_set.qidlestart; |
7051703b9 [PKT_SCHED]: GRED... |
122 123 124 125 126 |
} static inline void gred_store_wred_set(struct gred_sched *table, struct gred_sched_data *q) { |
eeca6688d net_sched: red: s... |
127 |
table->wred_set.qavg = q->vars.qavg; |
ba1bf474e net_sched: gred: ... |
128 |
table->wred_set.qidlestart = q->vars.qidlestart; |
7051703b9 [PKT_SCHED]: GRED... |
129 |
} |
b38c7eef7 [PKT_SCHED]: GRED... |
130 131 132 133 |
static inline int gred_use_ecn(struct gred_sched *t) { return t->red_flags & TC_RED_ECN; } |
bdc450a0b [PKT_SCHED]: (G)R... |
134 135 136 137 |
static inline int gred_use_harddrop(struct gred_sched *t) { return t->red_flags & TC_RED_HARDDROP; } |
520ac30f4 net_sched: drop p... |
138 139 |
static int gred_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) |
1da177e4c Linux-2.6.12-rc2 |
140 |
{ |
cc7ec456f net_sched: cleanups |
141 142 |
struct gred_sched_data *q = NULL; struct gred_sched *t = qdisc_priv(sch); |
22b33429a [PKT_SCHED]: GRED... |
143 |
unsigned long qavg = 0; |
4a591834c [PKT_SCHED]: GRED... |
144 |
u16 dp = tc_index_to_dp(skb); |
1da177e4c Linux-2.6.12-rc2 |
145 |
|
cc7ec456f net_sched: cleanups |
146 |
if (dp >= t->DPs || (q = t->tab[dp]) == NULL) { |
18e3fb84e [PKT_SCHED]: GRED... |
147 |
dp = t->def; |
cc7ec456f net_sched: cleanups |
148 149 |
q = t->tab[dp]; if (!q) { |
18e3fb84e [PKT_SCHED]: GRED... |
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. */ |
a3eb95f89 net_sched: gred: ... |
154 155 |
if (likely(sch->qstats.backlog + qdisc_pkt_len(skb) <= sch->limit)) |
18e3fb84e [PKT_SCHED]: GRED... |
156 157 158 |
return qdisc_enqueue_tail(skb, sch); else goto drop; |
1da177e4c Linux-2.6.12-rc2 |
159 |
} |
18e3fb84e [PKT_SCHED]: GRED... |
160 |
|
eeca6688d net_sched: red: s... |
161 |
/* fix tc_index? --could be controversial but needed for |
1da177e4c Linux-2.6.12-rc2 |
162 |
requeueing */ |
18e3fb84e [PKT_SCHED]: GRED... |
163 |
skb->tc_index = (skb->tc_index & ~GRED_VQ_MASK) | dp; |
1da177e4c Linux-2.6.12-rc2 |
164 |
} |
e29fe837b net_sched: gred: ... |
165 |
/* sum up all the qaves of prios < ours to get the new qave */ |
d6fd4e966 [PKT_SCHED]: GRED... |
166 |
if (!gred_wred_mode(t) && gred_rio_mode(t)) { |
1e4dfaf9b [PKT_SCHED]: GRED... |
167 168 169 170 |
int i; for (i = 0; i < t->DPs; i++) { if (t->tab[i] && t->tab[i]->prio < q->prio && |
eeca6688d net_sched: red: s... |
171 172 |
!red_is_idling(&t->tab[i]->vars)) qavg += t->tab[i]->vars.qavg; |
1da177e4c Linux-2.6.12-rc2 |
173 |
} |
1e4dfaf9b [PKT_SCHED]: GRED... |
174 |
|
1da177e4c Linux-2.6.12-rc2 |
175 176 177 |
} q->packetsin++; |
0abf77e55 net_sched: Add ac... |
178 |
q->bytesin += qdisc_pkt_len(skb); |
1da177e4c Linux-2.6.12-rc2 |
179 |
|
1e4dfaf9b [PKT_SCHED]: GRED... |
180 |
if (gred_wred_mode(t)) |
7051703b9 [PKT_SCHED]: GRED... |
181 |
gred_load_wred_set(t, q); |
1da177e4c Linux-2.6.12-rc2 |
182 |
|
eeca6688d net_sched: red: s... |
183 184 185 |
q->vars.qavg = red_calc_qavg(&q->parms, &q->vars, gred_backlog(t, q, sch)); |
1da177e4c Linux-2.6.12-rc2 |
186 |
|
eeca6688d net_sched: red: s... |
187 188 |
if (red_is_idling(&q->vars)) red_end_of_idle_period(&q->vars); |
1da177e4c Linux-2.6.12-rc2 |
189 |
|
dea3f6285 [PKT_SCHED]: GRED... |
190 |
if (gred_wred_mode(t)) |
7051703b9 [PKT_SCHED]: GRED... |
191 |
gred_store_wred_set(t, q); |
1da177e4c Linux-2.6.12-rc2 |
192 |
|
eeca6688d net_sched: red: s... |
193 |
switch (red_action(&q->parms, &q->vars, q->vars.qavg + qavg)) { |
cc7ec456f net_sched: cleanups |
194 195 196 197 |
case RED_DONT_MARK: break; case RED_PROB_MARK: |
25331d6ce net: sched: imple... |
198 |
qdisc_qstats_overlimit(sch); |
cc7ec456f net_sched: cleanups |
199 200 201 202 203 204 205 206 207 |
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: |
25331d6ce net: sched: imple... |
208 |
qdisc_qstats_overlimit(sch); |
cc7ec456f net_sched: cleanups |
209 210 211 212 213 214 215 |
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 Linux-2.6.12-rc2 |
216 |
} |
22b33429a [PKT_SCHED]: GRED... |
217 |
|
145a42b3a net_sched: gred: ... |
218 |
if (gred_backlog(t, q, sch) + qdisc_pkt_len(skb) <= q->limit) { |
0abf77e55 net_sched: Add ac... |
219 |
q->backlog += qdisc_pkt_len(skb); |
edf7a7b1f [PKT_SCHED]: GRED... |
220 |
return qdisc_enqueue_tail(skb, sch); |
1da177e4c Linux-2.6.12-rc2 |
221 |
} |
22b33429a [PKT_SCHED]: GRED... |
222 223 224 |
q->stats.pdrop++; drop: |
520ac30f4 net_sched: drop p... |
225 |
return qdisc_drop(skb, sch, to_free); |
c3b553cda [PKT_SCHED]: GRED... |
226 227 |
congestion_drop: |
520ac30f4 net_sched: drop p... |
228 |
qdisc_drop(skb, sch, to_free); |
c3b553cda [PKT_SCHED]: GRED... |
229 |
return NET_XMIT_CN; |
1da177e4c Linux-2.6.12-rc2 |
230 |
} |
cc7ec456f net_sched: cleanups |
231 |
static struct sk_buff *gred_dequeue(struct Qdisc *sch) |
1da177e4c Linux-2.6.12-rc2 |
232 233 |
{ struct sk_buff *skb; |
1e4dfaf9b [PKT_SCHED]: GRED... |
234 |
struct gred_sched *t = qdisc_priv(sch); |
1da177e4c Linux-2.6.12-rc2 |
235 |
|
edf7a7b1f [PKT_SCHED]: GRED... |
236 |
skb = qdisc_dequeue_head(sch); |
1da177e4c Linux-2.6.12-rc2 |
237 |
if (skb) { |
1e4dfaf9b [PKT_SCHED]: GRED... |
238 |
struct gred_sched_data *q; |
18e3fb84e [PKT_SCHED]: GRED... |
239 240 241 |
u16 dp = tc_index_to_dp(skb); if (dp >= t->DPs || (q = t->tab[dp]) == NULL) { |
e87cc4728 net: Convert net_... |
242 243 244 |
net_warn_ratelimited("GRED: Unable to relocate VQ 0x%x after dequeue, screwing up backlog ", tc_index_to_dp(skb)); |
18e3fb84e [PKT_SCHED]: GRED... |
245 |
} else { |
0abf77e55 net_sched: Add ac... |
246 |
q->backlog -= qdisc_pkt_len(skb); |
18e3fb84e [PKT_SCHED]: GRED... |
247 |
|
ba1bf474e net_sched: gred: ... |
248 249 250 251 252 253 254 |
if (gred_wred_mode(t)) { if (!sch->qstats.backlog) red_start_of_idle_period(&t->wred_set); } else { if (!q->backlog) red_start_of_idle_period(&q->vars); } |
1da177e4c Linux-2.6.12-rc2 |
255 |
} |
18e3fb84e [PKT_SCHED]: GRED... |
256 |
|
1da177e4c Linux-2.6.12-rc2 |
257 258 |
return skb; } |
1da177e4c Linux-2.6.12-rc2 |
259 260 |
return NULL; } |
cc7ec456f net_sched: cleanups |
261 |
static void gred_reset(struct Qdisc *sch) |
1da177e4c Linux-2.6.12-rc2 |
262 263 |
{ int i; |
1e4dfaf9b [PKT_SCHED]: GRED... |
264 |
struct gred_sched *t = qdisc_priv(sch); |
1da177e4c Linux-2.6.12-rc2 |
265 |
|
edf7a7b1f [PKT_SCHED]: GRED... |
266 |
qdisc_reset_queue(sch); |
1da177e4c Linux-2.6.12-rc2 |
267 |
|
10297b993 [NET] SCHED: Fix ... |
268 |
for (i = 0; i < t->DPs; i++) { |
1e4dfaf9b [PKT_SCHED]: GRED... |
269 270 271 272 |
struct gred_sched_data *q = t->tab[i]; if (!q) continue; |
eeca6688d net_sched: red: s... |
273 |
red_restart(&q->vars); |
1da177e4c Linux-2.6.12-rc2 |
274 |
q->backlog = 0; |
1da177e4c Linux-2.6.12-rc2 |
275 276 |
} } |
6639607ed [PKT_SCHED]: GRED... |
277 278 279 280 |
static inline void gred_destroy_vq(struct gred_sched_data *q) { kfree(q); } |
1e90474c3 [NET_SCHED]: Conv... |
281 |
static inline int gred_change_table_def(struct Qdisc *sch, struct nlattr *dps) |
1da177e4c Linux-2.6.12-rc2 |
282 283 |
{ struct gred_sched *table = qdisc_priv(sch); |
1da177e4c Linux-2.6.12-rc2 |
284 |
struct tc_gred_sopt *sopt; |
6639607ed [PKT_SCHED]: GRED... |
285 |
int i; |
1da177e4c Linux-2.6.12-rc2 |
286 |
|
27a3421e4 [NET_SCHED]: Use ... |
287 |
if (dps == NULL) |
1da177e4c Linux-2.6.12-rc2 |
288 |
return -EINVAL; |
1e90474c3 [NET_SCHED]: Conv... |
289 |
sopt = nla_data(dps); |
1da177e4c Linux-2.6.12-rc2 |
290 |
|
6639607ed [PKT_SCHED]: GRED... |
291 292 |
if (sopt->DPs > MAX_DPs || sopt->DPs == 0 || sopt->def_DP >= sopt->DPs) return -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
293 |
|
6639607ed [PKT_SCHED]: GRED... |
294 295 296 |
sch_tree_lock(sch); table->DPs = sopt->DPs; table->def = sopt->def_DP; |
b38c7eef7 [PKT_SCHED]: GRED... |
297 |
table->red_flags = sopt->flags; |
dea3f6285 [PKT_SCHED]: GRED... |
298 |
|
6639607ed [PKT_SCHED]: GRED... |
299 300 301 302 303 304 |
/* * 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 [PKT_SCHED]: GRED... |
305 |
|
6639607ed [PKT_SCHED]: GRED... |
306 307 308 309 310 311 312 313 314 315 316 317 |
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]) { |
c17988a90 net_sched: replac... |
318 319 320 |
pr_warn("GRED: Warning: Destroying shadowed VQ 0x%x ", i); |
6639607ed [PKT_SCHED]: GRED... |
321 322 |
gred_destroy_vq(table->tab[i]); table->tab[i] = NULL; |
10297b993 [NET] SCHED: Fix ... |
323 |
} |
6639607ed [PKT_SCHED]: GRED... |
324 |
} |
1da177e4c Linux-2.6.12-rc2 |
325 |
|
6639607ed [PKT_SCHED]: GRED... |
326 327 |
return 0; } |
f62d6b936 [PKT_SCHED]: GRED... |
328 |
static inline int gred_change_vq(struct Qdisc *sch, int dp, |
a73ed26bb sch_red: generali... |
329 |
struct tc_gred_qopt *ctl, int prio, |
869aa4104 sch_gred: prefer ... |
330 331 |
u8 *stab, u32 max_P, struct gred_sched_data **prealloc) |
6639607ed [PKT_SCHED]: GRED... |
332 333 |
{ struct gred_sched *table = qdisc_priv(sch); |
869aa4104 sch_gred: prefer ... |
334 |
struct gred_sched_data *q = table->tab[dp]; |
f62d6b936 [PKT_SCHED]: GRED... |
335 |
|
8001a37b8 net_sched: red: A... |
336 337 |
if (!red_check_params(ctl->qth_min, ctl->qth_max, ctl->Wlog)) return -EINVAL; |
869aa4104 sch_gred: prefer ... |
338 339 340 341 |
if (!q) { table->tab[dp] = q = *prealloc; *prealloc = NULL; if (!q) |
f62d6b936 [PKT_SCHED]: GRED... |
342 |
return -ENOMEM; |
f62d6b936 [PKT_SCHED]: GRED... |
343 |
} |
f62d6b936 [PKT_SCHED]: GRED... |
344 345 |
q->DP = dp; q->prio = prio; |
a3eb95f89 net_sched: gred: ... |
346 347 348 349 |
if (ctl->limit > sch->limit) q->limit = sch->limit; else q->limit = ctl->limit; |
22b33429a [PKT_SCHED]: GRED... |
350 351 |
if (q->backlog == 0) |
eeca6688d net_sched: red: s... |
352 |
red_end_of_idle_period(&q->vars); |
22b33429a [PKT_SCHED]: GRED... |
353 354 355 |
red_set_parms(&q->parms, ctl->qth_min, ctl->qth_max, ctl->Wlog, ctl->Plog, |
a73ed26bb sch_red: generali... |
356 |
ctl->Scell_log, stab, max_P); |
eeca6688d net_sched: red: s... |
357 |
red_set_vars(&q->vars); |
f62d6b936 [PKT_SCHED]: GRED... |
358 359 |
return 0; } |
27a3421e4 [NET_SCHED]: Use ... |
360 361 362 363 |
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 sch_red: generali... |
364 |
[TCA_GRED_MAX_P] = { .type = NLA_U32 }, |
a3eb95f89 net_sched: gred: ... |
365 |
[TCA_GRED_LIMIT] = { .type = NLA_U32 }, |
27a3421e4 [NET_SCHED]: Use ... |
366 |
}; |
1e90474c3 [NET_SCHED]: Conv... |
367 |
static int gred_change(struct Qdisc *sch, struct nlattr *opt) |
f62d6b936 [PKT_SCHED]: GRED... |
368 369 |
{ struct gred_sched *table = qdisc_priv(sch); |
6639607ed [PKT_SCHED]: GRED... |
370 |
struct tc_gred_qopt *ctl; |
1e90474c3 [NET_SCHED]: Conv... |
371 |
struct nlattr *tb[TCA_GRED_MAX + 1]; |
cee63723b [NET_SCHED]: Prop... |
372 |
int err, prio = GRED_DEF_PRIO; |
f62d6b936 [PKT_SCHED]: GRED... |
373 |
u8 *stab; |
a73ed26bb sch_red: generali... |
374 |
u32 max_P; |
869aa4104 sch_gred: prefer ... |
375 |
struct gred_sched_data *prealloc; |
6639607ed [PKT_SCHED]: GRED... |
376 |
|
cee63723b [NET_SCHED]: Prop... |
377 |
if (opt == NULL) |
6639607ed [PKT_SCHED]: GRED... |
378 |
return -EINVAL; |
fceb6435e netlink: pass ext... |
379 |
err = nla_parse_nested(tb, TCA_GRED_MAX, opt, gred_policy, NULL); |
cee63723b [NET_SCHED]: Prop... |
380 381 |
if (err < 0) return err; |
a3eb95f89 net_sched: gred: ... |
382 383 384 |
if (tb[TCA_GRED_PARMS] == NULL && tb[TCA_GRED_STAB] == NULL) { if (tb[TCA_GRED_LIMIT] != NULL) sch->limit = nla_get_u32(tb[TCA_GRED_LIMIT]); |
29d871195 net: sched: gred:... |
385 |
return gred_change_table_def(sch, tb[TCA_GRED_DPS]); |
a3eb95f89 net_sched: gred: ... |
386 |
} |
1da177e4c Linux-2.6.12-rc2 |
387 |
|
1e90474c3 [NET_SCHED]: Conv... |
388 |
if (tb[TCA_GRED_PARMS] == NULL || |
a3eb95f89 net_sched: gred: ... |
389 390 |
tb[TCA_GRED_STAB] == NULL || tb[TCA_GRED_LIMIT] != NULL) |
f62d6b936 [PKT_SCHED]: GRED... |
391 |
return -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
392 |
|
a73ed26bb sch_red: generali... |
393 |
max_P = tb[TCA_GRED_MAX_P] ? nla_get_u32(tb[TCA_GRED_MAX_P]) : 0; |
cee63723b [NET_SCHED]: Prop... |
394 |
err = -EINVAL; |
1e90474c3 [NET_SCHED]: Conv... |
395 396 |
ctl = nla_data(tb[TCA_GRED_PARMS]); stab = nla_data(tb[TCA_GRED_STAB]); |
a8aaa9958 [PKT_SCHED]: GRED... |
397 398 |
if (ctl->DP >= table->DPs) |
f62d6b936 [PKT_SCHED]: GRED... |
399 |
goto errout; |
1da177e4c Linux-2.6.12-rc2 |
400 |
|
d6fd4e966 [PKT_SCHED]: GRED... |
401 |
if (gred_rio_mode(table)) { |
f62d6b936 [PKT_SCHED]: GRED... |
402 403 404 405 406 407 408 409 410 411 412 413 414 |
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 Linux-2.6.12-rc2 |
415 |
} |
869aa4104 sch_gred: prefer ... |
416 |
prealloc = kzalloc(sizeof(*prealloc), GFP_KERNEL); |
f62d6b936 [PKT_SCHED]: GRED... |
417 |
sch_tree_lock(sch); |
1da177e4c Linux-2.6.12-rc2 |
418 |
|
869aa4104 sch_gred: prefer ... |
419 |
err = gred_change_vq(sch, ctl->DP, ctl, prio, stab, max_P, &prealloc); |
f62d6b936 [PKT_SCHED]: GRED... |
420 421 |
if (err < 0) goto errout_locked; |
1da177e4c Linux-2.6.12-rc2 |
422 |
|
d6fd4e966 [PKT_SCHED]: GRED... |
423 |
if (gred_rio_mode(table)) { |
dea3f6285 [PKT_SCHED]: GRED... |
424 425 426 |
gred_disable_wred_mode(table); if (gred_wred_mode_check(sch)) gred_enable_wred_mode(table); |
1da177e4c Linux-2.6.12-rc2 |
427 |
} |
f62d6b936 [PKT_SCHED]: GRED... |
428 |
err = 0; |
1da177e4c Linux-2.6.12-rc2 |
429 |
|
f62d6b936 [PKT_SCHED]: GRED... |
430 431 |
errout_locked: sch_tree_unlock(sch); |
869aa4104 sch_gred: prefer ... |
432 |
kfree(prealloc); |
f62d6b936 [PKT_SCHED]: GRED... |
433 434 |
errout: return err; |
1da177e4c Linux-2.6.12-rc2 |
435 |
} |
1e90474c3 [NET_SCHED]: Conv... |
436 |
static int gred_init(struct Qdisc *sch, struct nlattr *opt) |
1da177e4c Linux-2.6.12-rc2 |
437 |
{ |
1e90474c3 [NET_SCHED]: Conv... |
438 |
struct nlattr *tb[TCA_GRED_MAX + 1]; |
cee63723b [NET_SCHED]: Prop... |
439 |
int err; |
1da177e4c Linux-2.6.12-rc2 |
440 |
|
cee63723b [NET_SCHED]: Prop... |
441 |
if (opt == NULL) |
1da177e4c Linux-2.6.12-rc2 |
442 |
return -EINVAL; |
fceb6435e netlink: pass ext... |
443 |
err = nla_parse_nested(tb, TCA_GRED_MAX, opt, gred_policy, NULL); |
cee63723b [NET_SCHED]: Prop... |
444 445 |
if (err < 0) return err; |
1e90474c3 [NET_SCHED]: Conv... |
446 |
if (tb[TCA_GRED_PARMS] || tb[TCA_GRED_STAB]) |
6639607ed [PKT_SCHED]: GRED... |
447 |
return -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
448 |
|
a3eb95f89 net_sched: gred: ... |
449 450 |
if (tb[TCA_GRED_LIMIT]) sch->limit = nla_get_u32(tb[TCA_GRED_LIMIT]); |
348e3435c net: sched: drop ... |
451 452 453 |
else sch->limit = qdisc_dev(sch)->tx_queue_len * psched_mtu(qdisc_dev(sch)); |
a3eb95f89 net_sched: gred: ... |
454 |
|
1e90474c3 [NET_SCHED]: Conv... |
455 |
return gred_change_table_def(sch, tb[TCA_GRED_DPS]); |
1da177e4c Linux-2.6.12-rc2 |
456 457 458 459 |
} static int gred_dump(struct Qdisc *sch, struct sk_buff *skb) { |
1da177e4c Linux-2.6.12-rc2 |
460 |
struct gred_sched *table = qdisc_priv(sch); |
1e90474c3 [NET_SCHED]: Conv... |
461 |
struct nlattr *parms, *opts = NULL; |
1da177e4c Linux-2.6.12-rc2 |
462 |
int i; |
a73ed26bb sch_red: generali... |
463 |
u32 max_p[MAX_DPs]; |
e06368221 [PKT_SCHED]: GRED... |
464 465 466 467 |
struct tc_gred_sopt sopt = { .DPs = table->DPs, .def_DP = table->def, .grio = gred_rio_mode(table), |
b38c7eef7 [PKT_SCHED]: GRED... |
468 |
.flags = table->red_flags, |
e06368221 [PKT_SCHED]: GRED... |
469 |
}; |
1da177e4c Linux-2.6.12-rc2 |
470 |
|
1e90474c3 [NET_SCHED]: Conv... |
471 472 473 |
opts = nla_nest_start(skb, TCA_OPTIONS); if (opts == NULL) goto nla_put_failure; |
1b34ec43c pkt_sched: Stop u... |
474 475 |
if (nla_put(skb, TCA_GRED_DPS, sizeof(sopt), &sopt)) goto nla_put_failure; |
a73ed26bb sch_red: generali... |
476 477 478 479 480 481 |
for (i = 0; i < MAX_DPs; i++) { struct gred_sched_data *q = table->tab[i]; max_p[i] = q ? q->parms.max_P : 0; } |
1b34ec43c pkt_sched: Stop u... |
482 483 |
if (nla_put(skb, TCA_GRED_MAX_P, sizeof(max_p), max_p)) goto nla_put_failure; |
a73ed26bb sch_red: generali... |
484 |
|
a3eb95f89 net_sched: gred: ... |
485 486 |
if (nla_put_u32(skb, TCA_GRED_LIMIT, sch->limit)) goto nla_put_failure; |
1e90474c3 [NET_SCHED]: Conv... |
487 488 489 |
parms = nla_nest_start(skb, TCA_GRED_PARMS); if (parms == NULL) goto nla_put_failure; |
1da177e4c Linux-2.6.12-rc2 |
490 |
|
05f1cc01b [PKT_SCHED]: GRED... |
491 492 493 |
for (i = 0; i < MAX_DPs; i++) { struct gred_sched_data *q = table->tab[i]; struct tc_gred_qopt opt; |
1fe37b106 net_sched: gred: ... |
494 |
unsigned long qavg; |
1da177e4c Linux-2.6.12-rc2 |
495 |
|
05f1cc01b [PKT_SCHED]: GRED... |
496 |
memset(&opt, 0, sizeof(opt)); |
1da177e4c Linux-2.6.12-rc2 |
497 498 499 500 501 |
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 [PKT_SCHED]: GRED... |
502 503 |
opt.DP = MAX_DPs + i; goto append_opt; |
1da177e4c Linux-2.6.12-rc2 |
504 |
} |
05f1cc01b [PKT_SCHED]: GRED... |
505 506 |
opt.limit = q->limit; opt.DP = q->DP; |
145a42b3a net_sched: gred: ... |
507 |
opt.backlog = gred_backlog(table, q, sch); |
05f1cc01b [PKT_SCHED]: GRED... |
508 |
opt.prio = q->prio; |
22b33429a [PKT_SCHED]: GRED... |
509 510 511 512 513 514 515 516 517 |
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 [PKT_SCHED]: GRED... |
518 519 |
opt.packets = q->packetsin; opt.bytesin = q->bytesin; |
244b65dbf net_sched: gred: ... |
520 521 |
if (gred_wred_mode(table)) gred_load_wred_set(table, q); |
05f1cc01b [PKT_SCHED]: GRED... |
522 |
|
1fe37b106 net_sched: gred: ... |
523 524 525 |
qavg = red_calc_qavg(&q->parms, &q->vars, q->vars.qavg >> q->parms.Wlog); opt.qave = qavg >> q->parms.Wlog; |
22b33429a [PKT_SCHED]: GRED... |
526 |
|
05f1cc01b [PKT_SCHED]: GRED... |
527 |
append_opt: |
1e90474c3 [NET_SCHED]: Conv... |
528 529 |
if (nla_append(skb, sizeof(opt), &opt) < 0) goto nla_put_failure; |
1da177e4c Linux-2.6.12-rc2 |
530 |
} |
1e90474c3 [NET_SCHED]: Conv... |
531 |
nla_nest_end(skb, parms); |
1da177e4c Linux-2.6.12-rc2 |
532 |
|
1e90474c3 [NET_SCHED]: Conv... |
533 |
return nla_nest_end(skb, opts); |
1da177e4c Linux-2.6.12-rc2 |
534 |
|
1e90474c3 [NET_SCHED]: Conv... |
535 |
nla_put_failure: |
bc3ed28ca netlink: Improve ... |
536 537 |
nla_nest_cancel(skb, opts); return -EMSGSIZE; |
1da177e4c Linux-2.6.12-rc2 |
538 539 540 541 542 543 |
} static void gred_destroy(struct Qdisc *sch) { struct gred_sched *table = qdisc_priv(sch); int i; |
1e4dfaf9b [PKT_SCHED]: GRED... |
544 |
for (i = 0; i < table->DPs; i++) { |
1da177e4c Linux-2.6.12-rc2 |
545 |
if (table->tab[i]) |
6639607ed [PKT_SCHED]: GRED... |
546 |
gred_destroy_vq(table->tab[i]); |
1da177e4c Linux-2.6.12-rc2 |
547 548 |
} } |
20fea08b5 [NET]: Move Qdisc... |
549 |
static struct Qdisc_ops gred_qdisc_ops __read_mostly = { |
1da177e4c Linux-2.6.12-rc2 |
550 551 552 553 |
.id = "gred", .priv_size = sizeof(struct gred_sched), .enqueue = gred_enqueue, .dequeue = gred_dequeue, |
8e3af9789 pkt_sched: Add qd... |
554 |
.peek = qdisc_peek_head, |
1da177e4c Linux-2.6.12-rc2 |
555 556 557 558 559 560 561 562 563 564 565 566 |
.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 [PKT_SCHED]: GRED... |
567 568 |
static void __exit gred_module_exit(void) |
1da177e4c Linux-2.6.12-rc2 |
569 570 571 |
{ unregister_qdisc(&gred_qdisc_ops); } |
1e4dfaf9b [PKT_SCHED]: GRED... |
572 |
|
1da177e4c Linux-2.6.12-rc2 |
573 574 |
module_init(gred_module_init) module_exit(gred_module_exit) |
1e4dfaf9b [PKT_SCHED]: GRED... |
575 |
|
1da177e4c Linux-2.6.12-rc2 |
576 |
MODULE_LICENSE("GPL"); |