net_sched: Add accessor function for packet length for qdiscs
[linux-block.git] / net / sched / sch_netem.c
1 /*
2  * net/sched/sch_netem.c        Network emulator
3  *
4  *              This program is free software; you can redistribute it and/or
5  *              modify it under the terms of the GNU General Public License
6  *              as published by the Free Software Foundation; either version
7  *              2 of the License.
8  *
9  *              Many of the algorithms and ideas for this came from
10  *              NIST Net which is not copyrighted.
11  *
12  * Authors:     Stephen Hemminger <shemminger@osdl.org>
13  *              Catalin(ux aka Dino) BOIE <catab at umbrella dot ro>
14  */
15
16 #include <linux/module.h>
17 #include <linux/types.h>
18 #include <linux/kernel.h>
19 #include <linux/errno.h>
20 #include <linux/skbuff.h>
21 #include <linux/rtnetlink.h>
22
23 #include <net/netlink.h>
24 #include <net/pkt_sched.h>
25
26 #define VERSION "1.2"
27
28 /*      Network Emulation Queuing algorithm.
29         ====================================
30
31         Sources: [1] Mark Carson, Darrin Santay, "NIST Net - A Linux-based
32                  Network Emulation Tool
33                  [2] Luigi Rizzo, DummyNet for FreeBSD
34
35          ----------------------------------------------------------------
36
37          This started out as a simple way to delay outgoing packets to
38          test TCP but has grown to include most of the functionality
39          of a full blown network emulator like NISTnet. It can delay
40          packets and add random jitter (and correlation). The random
41          distribution can be loaded from a table as well to provide
42          normal, Pareto, or experimental curves. Packet loss,
43          duplication, and reordering can also be emulated.
44
45          This qdisc does not do classification that can be handled in
46          layering other disciplines.  It does not need to do bandwidth
47          control either since that can be handled by using token
48          bucket or other rate control.
49
50          The simulator is limited by the Linux timer resolution
51          and will create packet bursts on the HZ boundary (1ms).
52 */
53
54 struct netem_sched_data {
55         struct Qdisc    *qdisc;
56         struct qdisc_watchdog watchdog;
57
58         psched_tdiff_t latency;
59         psched_tdiff_t jitter;
60
61         u32 loss;
62         u32 limit;
63         u32 counter;
64         u32 gap;
65         u32 duplicate;
66         u32 reorder;
67         u32 corrupt;
68
69         struct crndstate {
70                 u32 last;
71                 u32 rho;
72         } delay_cor, loss_cor, dup_cor, reorder_cor, corrupt_cor;
73
74         struct disttable {
75                 u32  size;
76                 s16 table[0];
77         } *delay_dist;
78 };
79
80 /* Time stamp put into socket buffer control block */
81 struct netem_skb_cb {
82         psched_time_t   time_to_send;
83 };
84
85 static inline struct netem_skb_cb *netem_skb_cb(struct sk_buff *skb)
86 {
87         BUILD_BUG_ON(sizeof(skb->cb) < sizeof(struct netem_skb_cb));
88         return (struct netem_skb_cb *)skb->cb;
89 }
90
91 /* init_crandom - initialize correlated random number generator
92  * Use entropy source for initial seed.
93  */
94 static void init_crandom(struct crndstate *state, unsigned long rho)
95 {
96         state->rho = rho;
97         state->last = net_random();
98 }
99
100 /* get_crandom - correlated random number generator
101  * Next number depends on last value.
102  * rho is scaled to avoid floating point.
103  */
104 static u32 get_crandom(struct crndstate *state)
105 {
106         u64 value, rho;
107         unsigned long answer;
108
109         if (state->rho == 0)    /* no correlation */
110                 return net_random();
111
112         value = net_random();
113         rho = (u64)state->rho + 1;
114         answer = (value * ((1ull<<32) - rho) + state->last * rho) >> 32;
115         state->last = answer;
116         return answer;
117 }
118
119 /* tabledist - return a pseudo-randomly distributed value with mean mu and
120  * std deviation sigma.  Uses table lookup to approximate the desired
121  * distribution, and a uniformly-distributed pseudo-random source.
122  */
123 static psched_tdiff_t tabledist(psched_tdiff_t mu, psched_tdiff_t sigma,
124                                 struct crndstate *state,
125                                 const struct disttable *dist)
126 {
127         psched_tdiff_t x;
128         long t;
129         u32 rnd;
130
131         if (sigma == 0)
132                 return mu;
133
134         rnd = get_crandom(state);
135
136         /* default uniform distribution */
137         if (dist == NULL)
138                 return (rnd % (2*sigma)) - sigma + mu;
139
140         t = dist->table[rnd % dist->size];
141         x = (sigma % NETEM_DIST_SCALE) * t;
142         if (x >= 0)
143                 x += NETEM_DIST_SCALE/2;
144         else
145                 x -= NETEM_DIST_SCALE/2;
146
147         return  x / NETEM_DIST_SCALE + (sigma / NETEM_DIST_SCALE) * t + mu;
148 }
149
150 /*
151  * Insert one skb into qdisc.
152  * Note: parent depends on return value to account for queue length.
153  *      NET_XMIT_DROP: queue length didn't change.
154  *      NET_XMIT_SUCCESS: one skb was queued.
155  */
156 static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
157 {
158         struct netem_sched_data *q = qdisc_priv(sch);
159         /* We don't fill cb now as skb_unshare() may invalidate it */
160         struct netem_skb_cb *cb;
161         struct sk_buff *skb2;
162         int ret;
163         int count = 1;
164
165         pr_debug("netem_enqueue skb=%p\n", skb);
166
167         /* Random duplication */
168         if (q->duplicate && q->duplicate >= get_crandom(&q->dup_cor))
169                 ++count;
170
171         /* Random packet drop 0 => none, ~0 => all */
172         if (q->loss && q->loss >= get_crandom(&q->loss_cor))
173                 --count;
174
175         if (count == 0) {
176                 sch->qstats.drops++;
177                 kfree_skb(skb);
178                 return NET_XMIT_BYPASS;
179         }
180
181         skb_orphan(skb);
182
183         /*
184          * If we need to duplicate packet, then re-insert at top of the
185          * qdisc tree, since parent queuer expects that only one
186          * skb will be queued.
187          */
188         if (count > 1 && (skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) {
189                 struct Qdisc *rootq = qdisc_root(sch);
190                 u32 dupsave = q->duplicate; /* prevent duplicating a dup... */
191                 q->duplicate = 0;
192
193                 qdisc_enqueue_root(skb2, rootq);
194                 q->duplicate = dupsave;
195         }
196
197         /*
198          * Randomized packet corruption.
199          * Make copy if needed since we are modifying
200          * If packet is going to be hardware checksummed, then
201          * do it now in software before we mangle it.
202          */
203         if (q->corrupt && q->corrupt >= get_crandom(&q->corrupt_cor)) {
204                 if (!(skb = skb_unshare(skb, GFP_ATOMIC))
205                     || (skb->ip_summed == CHECKSUM_PARTIAL
206                         && skb_checksum_help(skb))) {
207                         sch->qstats.drops++;
208                         return NET_XMIT_DROP;
209                 }
210
211                 skb->data[net_random() % skb_headlen(skb)] ^= 1<<(net_random() % 8);
212         }
213
214         cb = netem_skb_cb(skb);
215         if (q->gap == 0                 /* not doing reordering */
216             || q->counter < q->gap      /* inside last reordering gap */
217             || q->reorder < get_crandom(&q->reorder_cor)) {
218                 psched_time_t now;
219                 psched_tdiff_t delay;
220
221                 delay = tabledist(q->latency, q->jitter,
222                                   &q->delay_cor, q->delay_dist);
223
224                 now = psched_get_time();
225                 cb->time_to_send = now + delay;
226                 ++q->counter;
227                 ret = qdisc_enqueue(skb, q->qdisc);
228         } else {
229                 /*
230                  * Do re-ordering by putting one out of N packets at the front
231                  * of the queue.
232                  */
233                 cb->time_to_send = psched_get_time();
234                 q->counter = 0;
235                 ret = q->qdisc->ops->requeue(skb, q->qdisc);
236         }
237
238         if (likely(ret == NET_XMIT_SUCCESS)) {
239                 sch->q.qlen++;
240                 sch->bstats.bytes += qdisc_pkt_len(skb);
241                 sch->bstats.packets++;
242         } else
243                 sch->qstats.drops++;
244
245         pr_debug("netem: enqueue ret %d\n", ret);
246         return ret;
247 }
248
249 /* Requeue packets but don't change time stamp */
250 static int netem_requeue(struct sk_buff *skb, struct Qdisc *sch)
251 {
252         struct netem_sched_data *q = qdisc_priv(sch);
253         int ret;
254
255         if ((ret = q->qdisc->ops->requeue(skb, q->qdisc)) == 0) {
256                 sch->q.qlen++;
257                 sch->qstats.requeues++;
258         }
259
260         return ret;
261 }
262
263 static unsigned int netem_drop(struct Qdisc* sch)
264 {
265         struct netem_sched_data *q = qdisc_priv(sch);
266         unsigned int len = 0;
267
268         if (q->qdisc->ops->drop && (len = q->qdisc->ops->drop(q->qdisc)) != 0) {
269                 sch->q.qlen--;
270                 sch->qstats.drops++;
271         }
272         return len;
273 }
274
275 static struct sk_buff *netem_dequeue(struct Qdisc *sch)
276 {
277         struct netem_sched_data *q = qdisc_priv(sch);
278         struct sk_buff *skb;
279
280         smp_mb();
281         if (sch->flags & TCQ_F_THROTTLED)
282                 return NULL;
283
284         skb = q->qdisc->dequeue(q->qdisc);
285         if (skb) {
286                 const struct netem_skb_cb *cb = netem_skb_cb(skb);
287                 psched_time_t now = psched_get_time();
288
289                 /* if more time remaining? */
290                 if (cb->time_to_send <= now) {
291                         pr_debug("netem_dequeue: return skb=%p\n", skb);
292                         sch->q.qlen--;
293                         return skb;
294                 }
295
296                 if (unlikely(q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS)) {
297                         qdisc_tree_decrease_qlen(q->qdisc, 1);
298                         sch->qstats.drops++;
299                         printk(KERN_ERR "netem: %s could not requeue\n",
300                                q->qdisc->ops->id);
301                 }
302
303                 qdisc_watchdog_schedule(&q->watchdog, cb->time_to_send);
304         }
305
306         return NULL;
307 }
308
309 static void netem_reset(struct Qdisc *sch)
310 {
311         struct netem_sched_data *q = qdisc_priv(sch);
312
313         qdisc_reset(q->qdisc);
314         sch->q.qlen = 0;
315         qdisc_watchdog_cancel(&q->watchdog);
316 }
317
318 /*
319  * Distribution data is a variable size payload containing
320  * signed 16 bit values.
321  */
322 static int get_dist_table(struct Qdisc *sch, const struct nlattr *attr)
323 {
324         struct netem_sched_data *q = qdisc_priv(sch);
325         unsigned long n = nla_len(attr)/sizeof(__s16);
326         const __s16 *data = nla_data(attr);
327         spinlock_t *root_lock;
328         struct disttable *d;
329         int i;
330
331         if (n > 65536)
332                 return -EINVAL;
333
334         d = kmalloc(sizeof(*d) + n*sizeof(d->table[0]), GFP_KERNEL);
335         if (!d)
336                 return -ENOMEM;
337
338         d->size = n;
339         for (i = 0; i < n; i++)
340                 d->table[i] = data[i];
341
342         root_lock = qdisc_root_lock(sch);
343
344         spin_lock_bh(root_lock);
345         d = xchg(&q->delay_dist, d);
346         spin_unlock_bh(root_lock);
347
348         kfree(d);
349         return 0;
350 }
351
352 static int get_correlation(struct Qdisc *sch, const struct nlattr *attr)
353 {
354         struct netem_sched_data *q = qdisc_priv(sch);
355         const struct tc_netem_corr *c = nla_data(attr);
356
357         init_crandom(&q->delay_cor, c->delay_corr);
358         init_crandom(&q->loss_cor, c->loss_corr);
359         init_crandom(&q->dup_cor, c->dup_corr);
360         return 0;
361 }
362
363 static int get_reorder(struct Qdisc *sch, const struct nlattr *attr)
364 {
365         struct netem_sched_data *q = qdisc_priv(sch);
366         const struct tc_netem_reorder *r = nla_data(attr);
367
368         q->reorder = r->probability;
369         init_crandom(&q->reorder_cor, r->correlation);
370         return 0;
371 }
372
373 static int get_corrupt(struct Qdisc *sch, const struct nlattr *attr)
374 {
375         struct netem_sched_data *q = qdisc_priv(sch);
376         const struct tc_netem_corrupt *r = nla_data(attr);
377
378         q->corrupt = r->probability;
379         init_crandom(&q->corrupt_cor, r->correlation);
380         return 0;
381 }
382
383 static const struct nla_policy netem_policy[TCA_NETEM_MAX + 1] = {
384         [TCA_NETEM_CORR]        = { .len = sizeof(struct tc_netem_corr) },
385         [TCA_NETEM_REORDER]     = { .len = sizeof(struct tc_netem_reorder) },
386         [TCA_NETEM_CORRUPT]     = { .len = sizeof(struct tc_netem_corrupt) },
387 };
388
389 /* Parse netlink message to set options */
390 static int netem_change(struct Qdisc *sch, struct nlattr *opt)
391 {
392         struct netem_sched_data *q = qdisc_priv(sch);
393         struct nlattr *tb[TCA_NETEM_MAX + 1];
394         struct tc_netem_qopt *qopt;
395         int ret;
396
397         if (opt == NULL)
398                 return -EINVAL;
399
400         ret = nla_parse_nested_compat(tb, TCA_NETEM_MAX, opt, netem_policy,
401                                       qopt, sizeof(*qopt));
402         if (ret < 0)
403                 return ret;
404
405         ret = fifo_set_limit(q->qdisc, qopt->limit);
406         if (ret) {
407                 pr_debug("netem: can't set fifo limit\n");
408                 return ret;
409         }
410
411         q->latency = qopt->latency;
412         q->jitter = qopt->jitter;
413         q->limit = qopt->limit;
414         q->gap = qopt->gap;
415         q->counter = 0;
416         q->loss = qopt->loss;
417         q->duplicate = qopt->duplicate;
418
419         /* for compatibility with earlier versions.
420          * if gap is set, need to assume 100% probability
421          */
422         if (q->gap)
423                 q->reorder = ~0;
424
425         if (tb[TCA_NETEM_CORR]) {
426                 ret = get_correlation(sch, tb[TCA_NETEM_CORR]);
427                 if (ret)
428                         return ret;
429         }
430
431         if (tb[TCA_NETEM_DELAY_DIST]) {
432                 ret = get_dist_table(sch, tb[TCA_NETEM_DELAY_DIST]);
433                 if (ret)
434                         return ret;
435         }
436
437         if (tb[TCA_NETEM_REORDER]) {
438                 ret = get_reorder(sch, tb[TCA_NETEM_REORDER]);
439                 if (ret)
440                         return ret;
441         }
442
443         if (tb[TCA_NETEM_CORRUPT]) {
444                 ret = get_corrupt(sch, tb[TCA_NETEM_CORRUPT]);
445                 if (ret)
446                         return ret;
447         }
448
449         return 0;
450 }
451
452 /*
453  * Special case version of FIFO queue for use by netem.
454  * It queues in order based on timestamps in skb's
455  */
456 struct fifo_sched_data {
457         u32 limit;
458         psched_time_t oldest;
459 };
460
461 static int tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch)
462 {
463         struct fifo_sched_data *q = qdisc_priv(sch);
464         struct sk_buff_head *list = &sch->q;
465         psched_time_t tnext = netem_skb_cb(nskb)->time_to_send;
466         struct sk_buff *skb;
467
468         if (likely(skb_queue_len(list) < q->limit)) {
469                 /* Optimize for add at tail */
470                 if (likely(skb_queue_empty(list) || tnext >= q->oldest)) {
471                         q->oldest = tnext;
472                         return qdisc_enqueue_tail(nskb, sch);
473                 }
474
475                 skb_queue_reverse_walk(list, skb) {
476                         const struct netem_skb_cb *cb = netem_skb_cb(skb);
477
478                         if (tnext >= cb->time_to_send)
479                                 break;
480                 }
481
482                 __skb_queue_after(list, skb, nskb);
483
484                 sch->qstats.backlog += qdisc_pkt_len(nskb);
485                 sch->bstats.bytes += qdisc_pkt_len(nskb);
486                 sch->bstats.packets++;
487
488                 return NET_XMIT_SUCCESS;
489         }
490
491         return qdisc_reshape_fail(nskb, sch);
492 }
493
494 static int tfifo_init(struct Qdisc *sch, struct nlattr *opt)
495 {
496         struct fifo_sched_data *q = qdisc_priv(sch);
497
498         if (opt) {
499                 struct tc_fifo_qopt *ctl = nla_data(opt);
500                 if (nla_len(opt) < sizeof(*ctl))
501                         return -EINVAL;
502
503                 q->limit = ctl->limit;
504         } else
505                 q->limit = max_t(u32, qdisc_dev(sch)->tx_queue_len, 1);
506
507         q->oldest = PSCHED_PASTPERFECT;
508         return 0;
509 }
510
511 static int tfifo_dump(struct Qdisc *sch, struct sk_buff *skb)
512 {
513         struct fifo_sched_data *q = qdisc_priv(sch);
514         struct tc_fifo_qopt opt = { .limit = q->limit };
515
516         NLA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
517         return skb->len;
518
519 nla_put_failure:
520         return -1;
521 }
522
523 static struct Qdisc_ops tfifo_qdisc_ops __read_mostly = {
524         .id             =       "tfifo",
525         .priv_size      =       sizeof(struct fifo_sched_data),
526         .enqueue        =       tfifo_enqueue,
527         .dequeue        =       qdisc_dequeue_head,
528         .requeue        =       qdisc_requeue,
529         .drop           =       qdisc_queue_drop,
530         .init           =       tfifo_init,
531         .reset          =       qdisc_reset_queue,
532         .change         =       tfifo_init,
533         .dump           =       tfifo_dump,
534 };
535
536 static int netem_init(struct Qdisc *sch, struct nlattr *opt)
537 {
538         struct netem_sched_data *q = qdisc_priv(sch);
539         int ret;
540
541         if (!opt)
542                 return -EINVAL;
543
544         qdisc_watchdog_init(&q->watchdog, sch);
545
546         q->qdisc = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue,
547                                      &tfifo_qdisc_ops,
548                                      TC_H_MAKE(sch->handle, 1));
549         if (!q->qdisc) {
550                 pr_debug("netem: qdisc create failed\n");
551                 return -ENOMEM;
552         }
553
554         ret = netem_change(sch, opt);
555         if (ret) {
556                 pr_debug("netem: change failed\n");
557                 qdisc_destroy(q->qdisc);
558         }
559         return ret;
560 }
561
562 static void netem_destroy(struct Qdisc *sch)
563 {
564         struct netem_sched_data *q = qdisc_priv(sch);
565
566         qdisc_watchdog_cancel(&q->watchdog);
567         qdisc_destroy(q->qdisc);
568         kfree(q->delay_dist);
569 }
570
571 static int netem_dump(struct Qdisc *sch, struct sk_buff *skb)
572 {
573         const struct netem_sched_data *q = qdisc_priv(sch);
574         unsigned char *b = skb_tail_pointer(skb);
575         struct nlattr *nla = (struct nlattr *) b;
576         struct tc_netem_qopt qopt;
577         struct tc_netem_corr cor;
578         struct tc_netem_reorder reorder;
579         struct tc_netem_corrupt corrupt;
580
581         qopt.latency = q->latency;
582         qopt.jitter = q->jitter;
583         qopt.limit = q->limit;
584         qopt.loss = q->loss;
585         qopt.gap = q->gap;
586         qopt.duplicate = q->duplicate;
587         NLA_PUT(skb, TCA_OPTIONS, sizeof(qopt), &qopt);
588
589         cor.delay_corr = q->delay_cor.rho;
590         cor.loss_corr = q->loss_cor.rho;
591         cor.dup_corr = q->dup_cor.rho;
592         NLA_PUT(skb, TCA_NETEM_CORR, sizeof(cor), &cor);
593
594         reorder.probability = q->reorder;
595         reorder.correlation = q->reorder_cor.rho;
596         NLA_PUT(skb, TCA_NETEM_REORDER, sizeof(reorder), &reorder);
597
598         corrupt.probability = q->corrupt;
599         corrupt.correlation = q->corrupt_cor.rho;
600         NLA_PUT(skb, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt);
601
602         nla->nla_len = skb_tail_pointer(skb) - b;
603
604         return skb->len;
605
606 nla_put_failure:
607         nlmsg_trim(skb, b);
608         return -1;
609 }
610
611 static int netem_dump_class(struct Qdisc *sch, unsigned long cl,
612                           struct sk_buff *skb, struct tcmsg *tcm)
613 {
614         struct netem_sched_data *q = qdisc_priv(sch);
615
616         if (cl != 1)    /* only one class */
617                 return -ENOENT;
618
619         tcm->tcm_handle |= TC_H_MIN(1);
620         tcm->tcm_info = q->qdisc->handle;
621
622         return 0;
623 }
624
625 static int netem_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
626                      struct Qdisc **old)
627 {
628         struct netem_sched_data *q = qdisc_priv(sch);
629
630         if (new == NULL)
631                 new = &noop_qdisc;
632
633         sch_tree_lock(sch);
634         *old = xchg(&q->qdisc, new);
635         qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
636         qdisc_reset(*old);
637         sch_tree_unlock(sch);
638
639         return 0;
640 }
641
642 static struct Qdisc *netem_leaf(struct Qdisc *sch, unsigned long arg)
643 {
644         struct netem_sched_data *q = qdisc_priv(sch);
645         return q->qdisc;
646 }
647
648 static unsigned long netem_get(struct Qdisc *sch, u32 classid)
649 {
650         return 1;
651 }
652
653 static void netem_put(struct Qdisc *sch, unsigned long arg)
654 {
655 }
656
657 static int netem_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
658                             struct nlattr **tca, unsigned long *arg)
659 {
660         return -ENOSYS;
661 }
662
663 static int netem_delete(struct Qdisc *sch, unsigned long arg)
664 {
665         return -ENOSYS;
666 }
667
668 static void netem_walk(struct Qdisc *sch, struct qdisc_walker *walker)
669 {
670         if (!walker->stop) {
671                 if (walker->count >= walker->skip)
672                         if (walker->fn(sch, 1, walker) < 0) {
673                                 walker->stop = 1;
674                                 return;
675                         }
676                 walker->count++;
677         }
678 }
679
680 static struct tcf_proto **netem_find_tcf(struct Qdisc *sch, unsigned long cl)
681 {
682         return NULL;
683 }
684
685 static const struct Qdisc_class_ops netem_class_ops = {
686         .graft          =       netem_graft,
687         .leaf           =       netem_leaf,
688         .get            =       netem_get,
689         .put            =       netem_put,
690         .change         =       netem_change_class,
691         .delete         =       netem_delete,
692         .walk           =       netem_walk,
693         .tcf_chain      =       netem_find_tcf,
694         .dump           =       netem_dump_class,
695 };
696
697 static struct Qdisc_ops netem_qdisc_ops __read_mostly = {
698         .id             =       "netem",
699         .cl_ops         =       &netem_class_ops,
700         .priv_size      =       sizeof(struct netem_sched_data),
701         .enqueue        =       netem_enqueue,
702         .dequeue        =       netem_dequeue,
703         .requeue        =       netem_requeue,
704         .drop           =       netem_drop,
705         .init           =       netem_init,
706         .reset          =       netem_reset,
707         .destroy        =       netem_destroy,
708         .change         =       netem_change,
709         .dump           =       netem_dump,
710         .owner          =       THIS_MODULE,
711 };
712
713
714 static int __init netem_module_init(void)
715 {
716         pr_info("netem: version " VERSION "\n");
717         return register_qdisc(&netem_qdisc_ops);
718 }
719 static void __exit netem_module_exit(void)
720 {
721         unregister_qdisc(&netem_qdisc_ops);
722 }
723 module_init(netem_module_init)
724 module_exit(netem_module_exit)
725 MODULE_LICENSE("GPL");