diff options
Diffstat (limited to 'include')
| -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; |
