diff options
Diffstat (limited to 'net/sched/sch_netem.c')
-rw-r--r-- | net/sched/sch_netem.c | 65 |
1 files changed, 26 insertions, 39 deletions
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index c9c649b26eaa..a59085700678 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c | |||
@@ -82,6 +82,13 @@ struct netem_skb_cb { | |||
82 | psched_time_t time_to_send; | 82 | psched_time_t time_to_send; |
83 | }; | 83 | }; |
84 | 84 | ||
85 | static inline struct netem_skb_cb *netem_skb_cb(struct sk_buff *skb) | ||
86 | { | ||
87 | BUILD_BUG_ON(sizeof(skb->cb) < | ||
88 | sizeof(struct qdisc_skb_cb) + sizeof(struct netem_skb_cb)); | ||
89 | return (struct netem_skb_cb *)qdisc_skb_cb(skb)->data; | ||
90 | } | ||
91 | |||
85 | /* init_crandom - initialize correlated random number generator | 92 | /* init_crandom - initialize correlated random number generator |
86 | * Use entropy source for initial seed. | 93 | * Use entropy source for initial seed. |
87 | */ | 94 | */ |
@@ -180,11 +187,11 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) | |||
180 | * skb will be queued. | 187 | * skb will be queued. |
181 | */ | 188 | */ |
182 | if (count > 1 && (skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) { | 189 | if (count > 1 && (skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) { |
183 | struct Qdisc *rootq = sch->dev->qdisc; | 190 | struct Qdisc *rootq = qdisc_root(sch); |
184 | u32 dupsave = q->duplicate; /* prevent duplicating a dup... */ | 191 | u32 dupsave = q->duplicate; /* prevent duplicating a dup... */ |
185 | q->duplicate = 0; | 192 | q->duplicate = 0; |
186 | 193 | ||
187 | rootq->enqueue(skb2, rootq); | 194 | qdisc_enqueue_root(skb2, rootq); |
188 | q->duplicate = dupsave; | 195 | q->duplicate = dupsave; |
189 | } | 196 | } |
190 | 197 | ||
@@ -205,7 +212,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) | |||
205 | skb->data[net_random() % skb_headlen(skb)] ^= 1<<(net_random() % 8); | 212 | skb->data[net_random() % skb_headlen(skb)] ^= 1<<(net_random() % 8); |
206 | } | 213 | } |
207 | 214 | ||
208 | cb = (struct netem_skb_cb *)skb->cb; | 215 | cb = netem_skb_cb(skb); |
209 | if (q->gap == 0 /* not doing reordering */ | 216 | if (q->gap == 0 /* not doing reordering */ |
210 | || q->counter < q->gap /* inside last reordering gap */ | 217 | || q->counter < q->gap /* inside last reordering gap */ |
211 | || q->reorder < get_crandom(&q->reorder_cor)) { | 218 | || q->reorder < get_crandom(&q->reorder_cor)) { |
@@ -218,7 +225,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) | |||
218 | now = psched_get_time(); | 225 | now = psched_get_time(); |
219 | cb->time_to_send = now + delay; | 226 | cb->time_to_send = now + delay; |
220 | ++q->counter; | 227 | ++q->counter; |
221 | ret = q->qdisc->enqueue(skb, q->qdisc); | 228 | ret = qdisc_enqueue(skb, q->qdisc); |
222 | } else { | 229 | } else { |
223 | /* | 230 | /* |
224 | * Do re-ordering by putting one out of N packets at the front | 231 | * Do re-ordering by putting one out of N packets at the front |
@@ -231,7 +238,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) | |||
231 | 238 | ||
232 | if (likely(ret == NET_XMIT_SUCCESS)) { | 239 | if (likely(ret == NET_XMIT_SUCCESS)) { |
233 | sch->q.qlen++; | 240 | sch->q.qlen++; |
234 | sch->bstats.bytes += skb->len; | 241 | sch->bstats.bytes += qdisc_pkt_len(skb); |
235 | sch->bstats.packets++; | 242 | sch->bstats.packets++; |
236 | } else | 243 | } else |
237 | sch->qstats.drops++; | 244 | sch->qstats.drops++; |
@@ -277,8 +284,7 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch) | |||
277 | 284 | ||
278 | skb = q->qdisc->dequeue(q->qdisc); | 285 | skb = q->qdisc->dequeue(q->qdisc); |
279 | if (skb) { | 286 | if (skb) { |
280 | const struct netem_skb_cb *cb | 287 | const struct netem_skb_cb *cb = netem_skb_cb(skb); |
281 | = (const struct netem_skb_cb *)skb->cb; | ||
282 | psched_time_t now = psched_get_time(); | 288 | psched_time_t now = psched_get_time(); |
283 | 289 | ||
284 | /* if more time remaining? */ | 290 | /* if more time remaining? */ |
@@ -310,28 +316,6 @@ static void netem_reset(struct Qdisc *sch) | |||
310 | qdisc_watchdog_cancel(&q->watchdog); | 316 | qdisc_watchdog_cancel(&q->watchdog); |
311 | } | 317 | } |
312 | 318 | ||
313 | /* Pass size change message down to embedded FIFO */ | ||
314 | static int set_fifo_limit(struct Qdisc *q, int limit) | ||
315 | { | ||
316 | struct nlattr *nla; | ||
317 | int ret = -ENOMEM; | ||
318 | |||
319 | /* Hack to avoid sending change message to non-FIFO */ | ||
320 | if (strncmp(q->ops->id + 1, "fifo", 4) != 0) | ||
321 | return 0; | ||
322 | |||
323 | nla = kmalloc(nla_attr_size(sizeof(struct tc_fifo_qopt)), GFP_KERNEL); | ||
324 | if (nla) { | ||
325 | nla->nla_type = RTM_NEWQDISC; | ||
326 | nla->nla_len = nla_attr_size(sizeof(struct tc_fifo_qopt)); | ||
327 | ((struct tc_fifo_qopt *)nla_data(nla))->limit = limit; | ||
328 | |||
329 | ret = q->ops->change(q, nla); | ||
330 | kfree(nla); | ||
331 | } | ||
332 | return ret; | ||
333 | } | ||
334 | |||
335 | /* | 319 | /* |
336 | * Distribution data is a variable size payload containing | 320 | * Distribution data is a variable size payload containing |
337 | * signed 16 bit values. | 321 | * signed 16 bit values. |
@@ -341,6 +325,7 @@ static int get_dist_table(struct Qdisc *sch, const struct nlattr *attr) | |||
341 | struct netem_sched_data *q = qdisc_priv(sch); | 325 | struct netem_sched_data *q = qdisc_priv(sch); |
342 | unsigned long n = nla_len(attr)/sizeof(__s16); | 326 | unsigned long n = nla_len(attr)/sizeof(__s16); |
343 | const __s16 *data = nla_data(attr); | 327 | const __s16 *data = nla_data(attr); |
328 | spinlock_t *root_lock; | ||
344 | struct disttable *d; | 329 | struct disttable *d; |
345 | int i; | 330 | int i; |
346 | 331 | ||
@@ -355,9 +340,11 @@ static int get_dist_table(struct Qdisc *sch, const struct nlattr *attr) | |||
355 | for (i = 0; i < n; i++) | 340 | for (i = 0; i < n; i++) |
356 | d->table[i] = data[i]; | 341 | d->table[i] = data[i]; |
357 | 342 | ||
358 | spin_lock_bh(&sch->dev->queue_lock); | 343 | root_lock = qdisc_root_lock(sch); |
344 | |||
345 | spin_lock_bh(root_lock); | ||
359 | d = xchg(&q->delay_dist, d); | 346 | d = xchg(&q->delay_dist, d); |
360 | spin_unlock_bh(&sch->dev->queue_lock); | 347 | spin_unlock_bh(root_lock); |
361 | 348 | ||
362 | kfree(d); | 349 | kfree(d); |
363 | return 0; | 350 | return 0; |
@@ -416,7 +403,7 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt) | |||
416 | if (ret < 0) | 403 | if (ret < 0) |
417 | return ret; | 404 | return ret; |
418 | 405 | ||
419 | ret = set_fifo_limit(q->qdisc, qopt->limit); | 406 | ret = fifo_set_limit(q->qdisc, qopt->limit); |
420 | if (ret) { | 407 | if (ret) { |
421 | pr_debug("netem: can't set fifo limit\n"); | 408 | pr_debug("netem: can't set fifo limit\n"); |
422 | return ret; | 409 | return ret; |
@@ -476,7 +463,7 @@ static int tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch) | |||
476 | { | 463 | { |
477 | struct fifo_sched_data *q = qdisc_priv(sch); | 464 | struct fifo_sched_data *q = qdisc_priv(sch); |
478 | struct sk_buff_head *list = &sch->q; | 465 | struct sk_buff_head *list = &sch->q; |
479 | psched_time_t tnext = ((struct netem_skb_cb *)nskb->cb)->time_to_send; | 466 | psched_time_t tnext = netem_skb_cb(nskb)->time_to_send; |
480 | struct sk_buff *skb; | 467 | struct sk_buff *skb; |
481 | 468 | ||
482 | if (likely(skb_queue_len(list) < q->limit)) { | 469 | if (likely(skb_queue_len(list) < q->limit)) { |
@@ -487,8 +474,7 @@ static int tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch) | |||
487 | } | 474 | } |
488 | 475 | ||
489 | skb_queue_reverse_walk(list, skb) { | 476 | skb_queue_reverse_walk(list, skb) { |
490 | const struct netem_skb_cb *cb | 477 | const struct netem_skb_cb *cb = netem_skb_cb(skb); |
491 | = (const struct netem_skb_cb *)skb->cb; | ||
492 | 478 | ||
493 | if (tnext >= cb->time_to_send) | 479 | if (tnext >= cb->time_to_send) |
494 | break; | 480 | break; |
@@ -496,8 +482,8 @@ static int tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch) | |||
496 | 482 | ||
497 | __skb_queue_after(list, skb, nskb); | 483 | __skb_queue_after(list, skb, nskb); |
498 | 484 | ||
499 | sch->qstats.backlog += nskb->len; | 485 | sch->qstats.backlog += qdisc_pkt_len(nskb); |
500 | sch->bstats.bytes += nskb->len; | 486 | sch->bstats.bytes += qdisc_pkt_len(nskb); |
501 | sch->bstats.packets++; | 487 | sch->bstats.packets++; |
502 | 488 | ||
503 | return NET_XMIT_SUCCESS; | 489 | return NET_XMIT_SUCCESS; |
@@ -517,7 +503,7 @@ static int tfifo_init(struct Qdisc *sch, struct nlattr *opt) | |||
517 | 503 | ||
518 | q->limit = ctl->limit; | 504 | q->limit = ctl->limit; |
519 | } else | 505 | } else |
520 | q->limit = max_t(u32, sch->dev->tx_queue_len, 1); | 506 | q->limit = max_t(u32, qdisc_dev(sch)->tx_queue_len, 1); |
521 | 507 | ||
522 | q->oldest = PSCHED_PASTPERFECT; | 508 | q->oldest = PSCHED_PASTPERFECT; |
523 | return 0; | 509 | return 0; |
@@ -558,7 +544,8 @@ static int netem_init(struct Qdisc *sch, struct nlattr *opt) | |||
558 | 544 | ||
559 | qdisc_watchdog_init(&q->watchdog, sch); | 545 | qdisc_watchdog_init(&q->watchdog, sch); |
560 | 546 | ||
561 | q->qdisc = qdisc_create_dflt(sch->dev, &tfifo_qdisc_ops, | 547 | q->qdisc = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, |
548 | &tfifo_qdisc_ops, | ||
562 | TC_H_MAKE(sch->handle, 1)); | 549 | TC_H_MAKE(sch->handle, 1)); |
563 | if (!q->qdisc) { | 550 | if (!q->qdisc) { |
564 | pr_debug("netem: qdisc create failed\n"); | 551 | pr_debug("netem: qdisc create failed\n"); |