Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

codel: generalize the implementation

This strips out qdisc specific bits from the code
and makes it slightly more reusable. Codel will be
used by wireless/mac80211 in the future.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Michal Kazior and committed by
David S. Miller
79bdc4c8 e425974f

+71 -32
+39 -25
include/net/codel.h
··· 176 176 177 177 #define CODEL_DISABLED_THRESHOLD INT_MAX 178 178 179 - static void codel_params_init(struct codel_params *params, 180 - const struct Qdisc *sch) 179 + static void codel_params_init(struct codel_params *params) 181 180 { 182 181 params->interval = MS2TIME(100); 183 182 params->target = MS2TIME(5); 184 - params->mtu = psched_mtu(qdisc_dev(sch)); 185 183 params->ce_threshold = CODEL_DISABLED_THRESHOLD; 186 184 params->ecn = false; 187 185 } ··· 224 226 return t + reciprocal_scale(interval, rec_inv_sqrt << REC_INV_SQRT_SHIFT); 225 227 } 226 228 229 + typedef u32 (*codel_skb_len_t)(const struct sk_buff *skb); 230 + typedef codel_time_t (*codel_skb_time_t)(const struct sk_buff *skb); 231 + typedef void (*codel_skb_drop_t)(struct sk_buff *skb, void *ctx); 232 + typedef struct sk_buff * (*codel_skb_dequeue_t)(struct codel_vars *vars, 233 + void *ctx); 234 + 227 235 static bool codel_should_drop(const struct sk_buff *skb, 228 - struct Qdisc *sch, 236 + void *ctx, 229 237 struct codel_vars *vars, 230 238 struct codel_params *params, 231 239 struct codel_stats *stats, 240 + codel_skb_len_t skb_len_func, 241 + codel_skb_time_t skb_time_func, 242 + u32 *backlog, 232 243 codel_time_t now) 233 244 { 234 245 bool ok_to_drop; 246 + u32 skb_len; 235 247 236 248 if (!skb) { 237 249 vars->first_above_time = 0; 238 250 return false; 239 251 } 240 252 241 - vars->ldelay = now - codel_get_enqueue_time(skb); 242 - sch->qstats.backlog -= qdisc_pkt_len(skb); 253 + skb_len = skb_len_func(skb); 254 + vars->ldelay = now - skb_time_func(skb); 243 255 244 - if (unlikely(qdisc_pkt_len(skb) > stats->maxpacket)) 245 - stats->maxpacket = qdisc_pkt_len(skb); 256 + if (unlikely(skb_len > stats->maxpacket)) 257 + stats->maxpacket = skb_len; 246 258 247 259 if (codel_time_before(vars->ldelay, params->target) || 248 - sch->qstats.backlog <= params->mtu) { 260 + *backlog <= params->mtu) { 249 261 /* went below - stay below for at least interval */ 250 262 vars->first_above_time = 0; 251 263 return false; ··· 272 264 return ok_to_drop; 273 265 } 274 266 275 - typedef struct sk_buff * (*codel_skb_dequeue_t)(struct codel_vars *vars, 276 - struct Qdisc *sch); 277 - 278 - static struct sk_buff *codel_dequeue(struct Qdisc *sch, 267 + static struct sk_buff *codel_dequeue(void *ctx, 268 + u32 *backlog, 279 269 struct codel_params *params, 280 270 struct codel_vars *vars, 281 271 struct codel_stats *stats, 272 + codel_skb_len_t skb_len_func, 273 + codel_skb_time_t skb_time_func, 274 + codel_skb_drop_t drop_func, 282 275 codel_skb_dequeue_t dequeue_func) 283 276 { 284 - struct sk_buff *skb = dequeue_func(vars, sch); 277 + struct sk_buff *skb = dequeue_func(vars, ctx); 285 278 codel_time_t now; 286 279 bool drop; 287 280 ··· 291 282 return skb; 292 283 } 293 284 now = codel_get_time(); 294 - drop = codel_should_drop(skb, sch, vars, params, stats, now); 285 + drop = codel_should_drop(skb, ctx, vars, params, stats, 286 + skb_len_func, skb_time_func, backlog, now); 295 287 if (vars->dropping) { 296 288 if (!drop) { 297 289 /* sojourn time below target - leave dropping state */ ··· 320 310 vars->rec_inv_sqrt); 321 311 goto end; 322 312 } 323 - stats->drop_len += qdisc_pkt_len(skb); 324 - qdisc_drop(skb, sch); 313 + stats->drop_len += skb_len_func(skb); 314 + drop_func(skb, ctx); 325 315 stats->drop_count++; 326 - skb = dequeue_func(vars, sch); 327 - if (!codel_should_drop(skb, sch, 328 - vars, params, stats, now)) { 316 + skb = dequeue_func(vars, ctx); 317 + if (!codel_should_drop(skb, ctx, 318 + vars, params, stats, 319 + skb_len_func, 320 + skb_time_func, 321 + backlog, now)) { 329 322 /* leave dropping state */ 330 323 vars->dropping = false; 331 324 } else { ··· 346 333 if (params->ecn && INET_ECN_set_ce(skb)) { 347 334 stats->ecn_mark++; 348 335 } else { 349 - stats->drop_len += qdisc_pkt_len(skb); 350 - qdisc_drop(skb, sch); 336 + stats->drop_len += skb_len_func(skb); 337 + drop_func(skb, ctx); 351 338 stats->drop_count++; 352 339 353 - skb = dequeue_func(vars, sch); 354 - drop = codel_should_drop(skb, sch, vars, params, 355 - stats, now); 340 + skb = dequeue_func(vars, ctx); 341 + drop = codel_should_drop(skb, ctx, vars, params, 342 + stats, skb_len_func, 343 + skb_time_func, backlog, now); 356 344 } 357 345 vars->dropping = true; 358 346 /* if min went above target close to when we last went below it
+17 -3
net/sched/sch_codel.c
··· 64 64 * to dequeue a packet from queue. Note: backlog is handled in 65 65 * codel, we dont need to reduce it here. 66 66 */ 67 - static struct sk_buff *dequeue(struct codel_vars *vars, struct Qdisc *sch) 67 + static struct sk_buff *dequeue_func(struct codel_vars *vars, void *ctx) 68 68 { 69 + struct Qdisc *sch = ctx; 69 70 struct sk_buff *skb = __skb_dequeue(&sch->q); 71 + 72 + if (skb) 73 + sch->qstats.backlog -= qdisc_pkt_len(skb); 70 74 71 75 prefetch(&skb->end); /* we'll need skb_shinfo() */ 72 76 return skb; 77 + } 78 + 79 + static void drop_func(struct sk_buff *skb, void *ctx) 80 + { 81 + struct Qdisc *sch = ctx; 82 + 83 + qdisc_drop(skb, sch); 73 84 } 74 85 75 86 static struct sk_buff *codel_qdisc_dequeue(struct Qdisc *sch) ··· 88 77 struct codel_sched_data *q = qdisc_priv(sch); 89 78 struct sk_buff *skb; 90 79 91 - skb = codel_dequeue(sch, &q->params, &q->vars, &q->stats, dequeue); 80 + skb = codel_dequeue(sch, &sch->qstats.backlog, &q->params, &q->vars, 81 + &q->stats, qdisc_pkt_len, codel_get_enqueue_time, 82 + drop_func, dequeue_func); 92 83 93 84 /* We cant call qdisc_tree_reduce_backlog() if our qlen is 0, 94 85 * or HTB crashes. Defer it for next round. ··· 186 173 187 174 sch->limit = DEFAULT_CODEL_LIMIT; 188 175 189 - codel_params_init(&q->params, sch); 176 + codel_params_init(&q->params); 190 177 codel_vars_init(&q->vars); 191 178 codel_stats_init(&q->stats); 179 + q->params.mtu = psched_mtu(qdisc_dev(sch)); 192 180 193 181 if (opt) { 194 182 int err = codel_change(sch, opt);
+15 -4
net/sched/sch_fq_codel.c
··· 220 220 * to dequeue a packet from queue. Note: backlog is handled in 221 221 * codel, we dont need to reduce it here. 222 222 */ 223 - static struct sk_buff *dequeue(struct codel_vars *vars, struct Qdisc *sch) 223 + static struct sk_buff *dequeue_func(struct codel_vars *vars, void *ctx) 224 224 { 225 + struct Qdisc *sch = ctx; 225 226 struct fq_codel_sched_data *q = qdisc_priv(sch); 226 227 struct fq_codel_flow *flow; 227 228 struct sk_buff *skb = NULL; ··· 232 231 skb = dequeue_head(flow); 233 232 q->backlogs[flow - q->flows] -= qdisc_pkt_len(skb); 234 233 sch->q.qlen--; 234 + sch->qstats.backlog -= qdisc_pkt_len(skb); 235 235 } 236 236 return skb; 237 + } 238 + 239 + static void drop_func(struct sk_buff *skb, void *ctx) 240 + { 241 + struct Qdisc *sch = ctx; 242 + 243 + qdisc_drop(skb, sch); 237 244 } 238 245 239 246 static struct sk_buff *fq_codel_dequeue(struct Qdisc *sch) ··· 272 263 prev_ecn_mark = q->cstats.ecn_mark; 273 264 prev_backlog = sch->qstats.backlog; 274 265 275 - skb = codel_dequeue(sch, &q->cparams, &flow->cvars, &q->cstats, 276 - dequeue); 266 + skb = codel_dequeue(sch, &sch->qstats.backlog, &q->cparams, 267 + &flow->cvars, &q->cstats, qdisc_pkt_len, 268 + codel_get_enqueue_time, drop_func, dequeue_func); 277 269 278 270 flow->dropped += q->cstats.drop_count - prev_drop_count; 279 271 flow->dropped += q->cstats.ecn_mark - prev_ecn_mark; ··· 433 423 q->perturbation = prandom_u32(); 434 424 INIT_LIST_HEAD(&q->new_flows); 435 425 INIT_LIST_HEAD(&q->old_flows); 436 - codel_params_init(&q->cparams, sch); 426 + codel_params_init(&q->cparams); 437 427 codel_stats_init(&q->cstats); 438 428 q->cparams.ecn = true; 429 + q->cparams.mtu = psched_mtu(qdisc_dev(sch)); 439 430 440 431 if (opt) { 441 432 int err = fq_codel_change(sch, opt);