diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2012-01-04 21:25:16 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-01-05 14:01:21 -0500 |
commit | eeca6688d6599c28bc449a45facb67d7f203be74 (patch) | |
tree | 5cabbf24a3c1ee2d7757c873ba6449296a8ef7b7 /include/net | |
parent | 18cb809850fb499ad9bf288696a95f4071f73931 (diff) |
net_sched: red: split red_parms into parms and vars
This patch splits the red_parms structure into two components.
One holding the RED 'constant' parameters, and one containing the
variables.
This permits a size reduction of GRED qdisc, and is a preliminary step
to add an optional RED unit to SFQ.
SFQRED will have a single red_parms structure shared by all flows, and a
private red_vars per flow.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
CC: Dave Taht <dave.taht@gmail.com>
CC: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include/net')
-rw-r--r-- | include/net/red.h | 98 |
1 files changed, 55 insertions, 43 deletions
diff --git a/include/net/red.h b/include/net/red.h index ef715a16cce4..baab385a4736 100644 --- a/include/net/red.h +++ b/include/net/red.h | |||
@@ -137,7 +137,9 @@ struct red_parms { | |||
137 | u8 Wlog; /* log(W) */ | 137 | u8 Wlog; /* log(W) */ |
138 | u8 Plog; /* random number bits */ | 138 | u8 Plog; /* random number bits */ |
139 | u8 Stab[RED_STAB_SIZE]; | 139 | u8 Stab[RED_STAB_SIZE]; |
140 | }; | ||
140 | 141 | ||
142 | struct red_vars { | ||
141 | /* Variables */ | 143 | /* Variables */ |
142 | int qcount; /* Number of packets since last random | 144 | int qcount; /* Number of packets since last random |
143 | number generation */ | 145 | number generation */ |
@@ -152,6 +154,16 @@ static inline u32 red_maxp(u8 Plog) | |||
152 | return Plog < 32 ? (~0U >> Plog) : ~0U; | 154 | return Plog < 32 ? (~0U >> Plog) : ~0U; |
153 | } | 155 | } |
154 | 156 | ||
157 | static inline void red_set_vars(struct red_vars *v) | ||
158 | { | ||
159 | /* Reset average queue length, the value is strictly bound | ||
160 | * to the parameters below, reseting hurts a bit but leaving | ||
161 | * it might result in an unreasonable qavg for a while. --TGR | ||
162 | */ | ||
163 | v->qavg = 0; | ||
164 | |||
165 | v->qcount = -1; | ||
166 | } | ||
155 | 167 | ||
156 | static inline void red_set_parms(struct red_parms *p, | 168 | static inline void red_set_parms(struct red_parms *p, |
157 | u32 qth_min, u32 qth_max, u8 Wlog, u8 Plog, | 169 | u32 qth_min, u32 qth_max, u8 Wlog, u8 Plog, |
@@ -160,13 +172,6 @@ static inline void red_set_parms(struct red_parms *p, | |||
160 | int delta = qth_max - qth_min; | 172 | int delta = qth_max - qth_min; |
161 | u32 max_p_delta; | 173 | u32 max_p_delta; |
162 | 174 | ||
163 | /* Reset average queue length, the value is strictly bound | ||
164 | * to the parameters below, reseting hurts a bit but leaving | ||
165 | * it might result in an unreasonable qavg for a while. --TGR | ||
166 | */ | ||
167 | p->qavg = 0; | ||
168 | |||
169 | p->qcount = -1; | ||
170 | p->qth_min = qth_min << Wlog; | 175 | p->qth_min = qth_min << Wlog; |
171 | p->qth_max = qth_max << Wlog; | 176 | p->qth_max = qth_max << Wlog; |
172 | p->Wlog = Wlog; | 177 | p->Wlog = Wlog; |
@@ -197,31 +202,32 @@ static inline void red_set_parms(struct red_parms *p, | |||
197 | memcpy(p->Stab, stab, sizeof(p->Stab)); | 202 | memcpy(p->Stab, stab, sizeof(p->Stab)); |
198 | } | 203 | } |
199 | 204 | ||
200 | static inline int red_is_idling(const struct red_parms *p) | 205 | static inline int red_is_idling(const struct red_vars *v) |
201 | { | 206 | { |
202 | return p->qidlestart.tv64 != 0; | 207 | return v->qidlestart.tv64 != 0; |
203 | } | 208 | } |
204 | 209 | ||
205 | static inline void red_start_of_idle_period(struct red_parms *p) | 210 | static inline void red_start_of_idle_period(struct red_vars *v) |
206 | { | 211 | { |
207 | p->qidlestart = ktime_get(); | 212 | v->qidlestart = ktime_get(); |
208 | } | 213 | } |
209 | 214 | ||
210 | static inline void red_end_of_idle_period(struct red_parms *p) | 215 | static inline void red_end_of_idle_period(struct red_vars *v) |
211 | { | 216 | { |
212 | p->qidlestart.tv64 = 0; | 217 | v->qidlestart.tv64 = 0; |
213 | } | 218 | } |
214 | 219 | ||
215 | static inline void red_restart(struct red_parms *p) | 220 | static inline void red_restart(struct red_vars *v) |
216 | { | 221 | { |
217 | red_end_of_idle_period(p); | 222 | red_end_of_idle_period(v); |
218 | p->qavg = 0; | 223 | v->qavg = 0; |
219 | p->qcount = -1; | 224 | v->qcount = -1; |
220 | } | 225 | } |
221 | 226 | ||
222 | static inline unsigned long red_calc_qavg_from_idle_time(const struct red_parms *p) | 227 | static inline unsigned long red_calc_qavg_from_idle_time(const struct red_parms *p, |
228 | const struct red_vars *v) | ||
223 | { | 229 | { |
224 | s64 delta = ktime_us_delta(ktime_get(), p->qidlestart); | 230 | s64 delta = ktime_us_delta(ktime_get(), v->qidlestart); |
225 | long us_idle = min_t(s64, delta, p->Scell_max); | 231 | long us_idle = min_t(s64, delta, p->Scell_max); |
226 | int shift; | 232 | int shift; |
227 | 233 | ||
@@ -248,7 +254,7 @@ static inline unsigned long red_calc_qavg_from_idle_time(const struct red_parms | |||
248 | shift = p->Stab[(us_idle >> p->Scell_log) & RED_STAB_MASK]; | 254 | shift = p->Stab[(us_idle >> p->Scell_log) & RED_STAB_MASK]; |
249 | 255 | ||
250 | if (shift) | 256 | if (shift) |
251 | return p->qavg >> shift; | 257 | return v->qavg >> shift; |
252 | else { | 258 | else { |
253 | /* Approximate initial part of exponent with linear function: | 259 | /* Approximate initial part of exponent with linear function: |
254 | * | 260 | * |
@@ -257,16 +263,17 @@ static inline unsigned long red_calc_qavg_from_idle_time(const struct red_parms | |||
257 | * Seems, it is the best solution to | 263 | * Seems, it is the best solution to |
258 | * problem of too coarse exponent tabulation. | 264 | * problem of too coarse exponent tabulation. |
259 | */ | 265 | */ |
260 | us_idle = (p->qavg * (u64)us_idle) >> p->Scell_log; | 266 | us_idle = (v->qavg * (u64)us_idle) >> p->Scell_log; |
261 | 267 | ||
262 | if (us_idle < (p->qavg >> 1)) | 268 | if (us_idle < (v->qavg >> 1)) |
263 | return p->qavg - us_idle; | 269 | return v->qavg - us_idle; |
264 | else | 270 | else |
265 | return p->qavg >> 1; | 271 | return v->qavg >> 1; |
266 | } | 272 | } |
267 | } | 273 | } |
268 | 274 | ||
269 | static inline unsigned long red_calc_qavg_no_idle_time(const struct red_parms *p, | 275 | static inline unsigned long red_calc_qavg_no_idle_time(const struct red_parms *p, |
276 | const struct red_vars *v, | ||
270 | unsigned int backlog) | 277 | unsigned int backlog) |
271 | { | 278 | { |
272 | /* | 279 | /* |
@@ -278,16 +285,17 @@ static inline unsigned long red_calc_qavg_no_idle_time(const struct red_parms *p | |||
278 | * | 285 | * |
279 | * --ANK (980924) | 286 | * --ANK (980924) |
280 | */ | 287 | */ |
281 | return p->qavg + (backlog - (p->qavg >> p->Wlog)); | 288 | return v->qavg + (backlog - (v->qavg >> p->Wlog)); |
282 | } | 289 | } |
283 | 290 | ||
284 | static inline unsigned long red_calc_qavg(const struct red_parms *p, | 291 | static inline unsigned long red_calc_qavg(const struct red_parms *p, |
292 | const struct red_vars *v, | ||
285 | unsigned int backlog) | 293 | unsigned int backlog) |
286 | { | 294 | { |
287 | if (!red_is_idling(p)) | 295 | if (!red_is_idling(v)) |
288 | return red_calc_qavg_no_idle_time(p, backlog); | 296 | return red_calc_qavg_no_idle_time(p, v, backlog); |
289 | else | 297 | else |
290 | return red_calc_qavg_from_idle_time(p); | 298 | return red_calc_qavg_from_idle_time(p, v); |
291 | } | 299 | } |
292 | 300 | ||
293 | 301 | ||
@@ -296,7 +304,9 @@ static inline u32 red_random(const struct red_parms *p) | |||
296 | return reciprocal_divide(net_random(), p->max_P_reciprocal); | 304 | return reciprocal_divide(net_random(), p->max_P_reciprocal); |
297 | } | 305 | } |
298 | 306 | ||
299 | static inline int red_mark_probability(const struct red_parms *p, unsigned long qavg) | 307 | static inline int red_mark_probability(const struct red_parms *p, |
308 | const struct red_vars *v, | ||
309 | unsigned long qavg) | ||
300 | { | 310 | { |
301 | /* The formula used below causes questions. | 311 | /* The formula used below causes questions. |
302 | 312 | ||
@@ -314,7 +324,7 @@ static inline int red_mark_probability(const struct red_parms *p, unsigned long | |||
314 | 324 | ||
315 | Any questions? --ANK (980924) | 325 | Any questions? --ANK (980924) |
316 | */ | 326 | */ |
317 | return !(((qavg - p->qth_min) >> p->Wlog) * p->qcount < p->qR); | 327 | return !(((qavg - p->qth_min) >> p->Wlog) * v->qcount < v->qR); |
318 | } | 328 | } |
319 | 329 | ||
320 | enum { | 330 | enum { |
@@ -323,7 +333,7 @@ enum { | |||
323 | RED_ABOVE_MAX_TRESH, | 333 | RED_ABOVE_MAX_TRESH, |
324 | }; | 334 | }; |
325 | 335 | ||
326 | static inline int red_cmp_thresh(struct red_parms *p, unsigned long qavg) | 336 | static inline int red_cmp_thresh(const struct red_parms *p, unsigned long qavg) |
327 | { | 337 | { |
328 | if (qavg < p->qth_min) | 338 | if (qavg < p->qth_min) |
329 | return RED_BELOW_MIN_THRESH; | 339 | return RED_BELOW_MIN_THRESH; |
@@ -339,27 +349,29 @@ enum { | |||
339 | RED_HARD_MARK, | 349 | RED_HARD_MARK, |
340 | }; | 350 | }; |
341 | 351 | ||
342 | static inline int red_action(struct red_parms *p, unsigned long qavg) | 352 | static inline int red_action(const struct red_parms *p, |
353 | struct red_vars *v, | ||
354 | unsigned long qavg) | ||
343 | { | 355 | { |
344 | switch (red_cmp_thresh(p, qavg)) { | 356 | switch (red_cmp_thresh(p, qavg)) { |
345 | case RED_BELOW_MIN_THRESH: | 357 | case RED_BELOW_MIN_THRESH: |
346 | p->qcount = -1; | 358 | v->qcount = -1; |
347 | return RED_DONT_MARK; | 359 | return RED_DONT_MARK; |
348 | 360 | ||
349 | case RED_BETWEEN_TRESH: | 361 | case RED_BETWEEN_TRESH: |
350 | if (++p->qcount) { | 362 | if (++v->qcount) { |
351 | if (red_mark_probability(p, qavg)) { | 363 | if (red_mark_probability(p, v, qavg)) { |
352 | p->qcount = 0; | 364 | v->qcount = 0; |
353 | p->qR = red_random(p); | 365 | v->qR = red_random(p); |
354 | return RED_PROB_MARK; | 366 | return RED_PROB_MARK; |
355 | } | 367 | } |
356 | } else | 368 | } else |
357 | p->qR = red_random(p); | 369 | v->qR = red_random(p); |
358 | 370 | ||
359 | return RED_DONT_MARK; | 371 | return RED_DONT_MARK; |
360 | 372 | ||
361 | case RED_ABOVE_MAX_TRESH: | 373 | case RED_ABOVE_MAX_TRESH: |
362 | p->qcount = -1; | 374 | v->qcount = -1; |
363 | return RED_HARD_MARK; | 375 | return RED_HARD_MARK; |
364 | } | 376 | } |
365 | 377 | ||
@@ -367,14 +379,14 @@ static inline int red_action(struct red_parms *p, unsigned long qavg) | |||
367 | return RED_DONT_MARK; | 379 | return RED_DONT_MARK; |
368 | } | 380 | } |
369 | 381 | ||
370 | static inline void red_adaptative_algo(struct red_parms *p) | 382 | static inline void red_adaptative_algo(struct red_parms *p, struct red_vars *v) |
371 | { | 383 | { |
372 | unsigned long qavg; | 384 | unsigned long qavg; |
373 | u32 max_p_delta; | 385 | u32 max_p_delta; |
374 | 386 | ||
375 | qavg = p->qavg; | 387 | qavg = v->qavg; |
376 | if (red_is_idling(p)) | 388 | if (red_is_idling(v)) |
377 | qavg = red_calc_qavg_from_idle_time(p); | 389 | qavg = red_calc_qavg_from_idle_time(p, v); |
378 | 390 | ||
379 | /* p->qavg is fixed point number with point at Wlog */ | 391 | /* p->qavg is fixed point number with point at Wlog */ |
380 | qavg >>= p->Wlog; | 392 | qavg >>= p->Wlog; |