aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/sch_netem.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched/sch_netem.c')
-rw-r--r--net/sched/sch_netem.c65
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
85static 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 */
314static 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");