sch_netem.c revision 07aaa11540828f4482c09e1a936a1f63cdb9fc9d
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * net/sched/sch_netem.c	Network emulator
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 		This program is free software; you can redistribute it and/or
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 		modify it under the terms of the GNU General Public License
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 		as published by the Free Software Foundation; either version
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 		2 of the License, or (at your option) any later version.
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  		Many of the algorithms and ideas for this came from
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		NIST Net which is not copyrighted.
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Authors:	Stephen Hemminger <shemminger@osdl.org>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		Catalin(ux aka Dino) BOIE <catab at umbrella dot ro>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/config.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bitops.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/rtnetlink.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/pkt_sched.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*	Network Emulation Queuing algorithm.
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	====================================
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Sources: [1] Mark Carson, Darrin Santay, "NIST Net - A Linux-based
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 Network Emulation Tool
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 [2] Luigi Rizzo, DummyNet for FreeBSD
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 ----------------------------------------------------------------
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 This started out as a simple way to delay outgoing packets to
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 test TCP but has grown to include most of the functionality
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 of a full blown network emulator like NISTnet. It can delay
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 packets and add random jitter (and correlation). The random
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 distribution can be loaded from a table as well to provide
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 normal, Pareto, or experimental curves. Packet loss,
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 duplication, and reordering can also be emulated.
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 This qdisc does not do classification that can be handled in
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 layering other disciplines.  It does not need to do bandwidth
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 control either since that can be handled by using token
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 bucket or other rate control.
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 The simulator is limited by the Linux timer resolution
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 and will create packet bursts on the HZ boundary (1ms).
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct netem_sched_data {
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc	*qdisc;
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct timer_list timer;
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 latency;
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 loss;
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 limit;
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 counter;
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 gap;
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 jitter;
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 duplicate;
650dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	u32 reorder;
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct crndstate {
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned long last;
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned long rho;
700dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	} delay_cor, loss_cor, dup_cor, reorder_cor;
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct disttable {
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u32  size;
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		s16 table[0];
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} *delay_dist;
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Time stamp put into socket buffer control block */
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct netem_skb_cb {
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psched_time_t	time_to_send;
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* init_crandom - initialize correlated random number generator
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Use entropy source for initial seed.
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void init_crandom(struct crndstate *state, unsigned long rho)
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	state->rho = rho;
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	state->last = net_random();
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* get_crandom - correlated random number generator
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Next number depends on last value.
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * rho is scaled to avoid floating point.
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long get_crandom(struct crndstate *state)
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u64 value, rho;
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long answer;
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (state->rho == 0)	/* no correllation */
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return net_random();
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	value = net_random();
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rho = (u64)state->rho + 1;
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	answer = (value * ((1ull<<32) - rho) + state->last * rho) >> 32;
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	state->last = answer;
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return answer;
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* tabledist - return a pseudo-randomly distributed value with mean mu and
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * std deviation sigma.  Uses table lookup to approximate the desired
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * distribution, and a uniformly-distributed pseudo-random source.
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic long tabledist(unsigned long mu, long sigma,
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		      struct crndstate *state, const struct disttable *dist)
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long t, x;
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long rnd;
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sigma == 0)
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return mu;
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rnd = get_crandom(state);
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* default uniform distribution */
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dist == NULL)
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (rnd % (2*sigma)) - sigma + mu;
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	t = dist->table[rnd % dist->size];
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	x = (sigma % NETEM_DIST_SCALE) * t;
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (x >= 0)
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		x += NETEM_DIST_SCALE/2;
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		x -= NETEM_DIST_SCALE/2;
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return  x / NETEM_DIST_SCALE + (sigma / NETEM_DIST_SCALE) * t + mu;
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1400afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger/*
1410afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger * Insert one skb into qdisc.
1420afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger * Note: parent depends on return value to account for queue length.
1430afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger * 	NET_XMIT_DROP: queue length didn't change.
1440afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger *      NET_XMIT_SUCCESS: one skb was queued.
1450afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger */
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netem_sched_data *q = qdisc_priv(sch);
1490f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger	struct netem_skb_cb *cb = (struct netem_skb_cb *)skb->cb;
1500afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	struct sk_buff *skb2;
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
1520afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	int count = 1;
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
154771018e76aaa6474be20a53c20458bcae8b00485Stephen Hemminger	pr_debug("netem_enqueue skb=%p\n", skb);
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1560afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	/* Random duplication */
1570afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	if (q->duplicate && q->duplicate >= get_crandom(&q->dup_cor))
1580afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger		++count;
1590afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Random packet drop 0 => none, ~0 => all */
1610afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	if (q->loss && q->loss >= get_crandom(&q->loss_cor))
1620afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger		--count;
1630afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger
1640afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	if (count == 0) {
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sch->qstats.drops++;
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree_skb(skb);
1670afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger		return NET_XMIT_DROP;
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1700afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	/*
1710afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	 * If we need to duplicate packet, then re-insert at top of the
1720afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	 * qdisc tree, since parent queuer expects that only one
1730afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	 * skb will be queued.
1740afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	 */
1750afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	if (count > 1 && (skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) {
1760afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger		struct Qdisc *rootq = sch->dev->qdisc;
1770afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger		u32 dupsave = q->duplicate; /* prevent duplicating a dup... */
1780afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger		q->duplicate = 0;
1790afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger
1800afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger		rootq->enqueue(skb2, rootq);
1810afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger		q->duplicate = dupsave;
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1840dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	if (q->gap == 0 		/* not doing reordering */
1850dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	    || q->counter < q->gap 	/* inside last reordering gap */
1860dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	    || q->reorder < get_crandom(&q->reorder_cor)) {
1870f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger		psched_time_t now;
18807aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger		psched_tdiff_t delay;
18907aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger
19007aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger		delay = tabledist(q->latency, q->jitter,
19107aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger				  &q->delay_cor, q->delay_dist);
19207aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger
1930f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger		PSCHED_GET_TIME(now);
19407aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger		PSCHED_TADD2(now, delay, cb->time_to_send);
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		++q->counter;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = q->qdisc->enqueue(skb, q->qdisc);
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
1980dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger		/*
1990dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger		 * Do re-ordering by putting one out of N packets at the front
2000dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger		 * of the queue.
2010dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger		 */
2020f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger		PSCHED_GET_TIME(cb->time_to_send);
2030dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger		q->counter = 0;
2040f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger		ret = q->qdisc->ops->requeue(skb, q->qdisc);
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (likely(ret == NET_XMIT_SUCCESS)) {
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sch->q.qlen++;
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sch->bstats.bytes += skb->len;
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sch->bstats.packets++;
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sch->qstats.drops++;
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
214d5d75cd6b10ddad2f375b61092754474ad78aec7Stephen Hemminger	pr_debug("netem: enqueue ret %d\n", ret);
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Requeue packets but don't change time stamp */
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int netem_requeue(struct sk_buff *skb, struct Qdisc *sch)
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netem_sched_data *q = qdisc_priv(sch);
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((ret = q->qdisc->ops->requeue(skb, q->qdisc)) == 0) {
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sch->q.qlen++;
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sch->qstats.requeues++;
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int netem_drop(struct Qdisc* sch)
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netem_sched_data *q = qdisc_priv(sch);
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int len;
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((len = q->qdisc->ops->drop(q->qdisc)) != 0) {
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sch->q.qlen--;
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sch->qstats.drops++;
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return len;
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sk_buff *netem_dequeue(struct Qdisc *sch)
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netem_sched_data *q = qdisc_priv(sch);
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb = q->qdisc->dequeue(q->qdisc);
250771018e76aaa6474be20a53c20458bcae8b00485Stephen Hemminger	if (skb) {
2510f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger		const struct netem_skb_cb *cb
2520f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger			= (const struct netem_skb_cb *)skb->cb;
2530f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger		psched_time_t now;
2540f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger
2550f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger		/* if more time remaining? */
2560f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger		PSCHED_GET_TIME(now);
25707aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger
25807aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger		if (PSCHED_TLESS(cb->time_to_send, now)) {
2590f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger			pr_debug("netem_dequeue: return skb=%p\n", skb);
2600f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger			sch->q.qlen--;
2610f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger			sch->flags &= ~TCQ_F_THROTTLED;
2620f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger			return skb;
26307aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger		} else {
26407aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger			psched_tdiff_t delay = PSCHED_TDIFF(cb->time_to_send, now);
2650f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger
26607aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger			if (q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS) {
26707aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger				sch->qstats.drops++;
268771018e76aaa6474be20a53c20458bcae8b00485Stephen Hemminger
26907aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger				/* After this qlen is confused */
27007aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger				printk(KERN_ERR "netem: queue discpline %s could not requeue\n",
27107aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger				       q->qdisc->ops->id);
27207aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger
27307aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger				sch->q.qlen--;
27407aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger			}
27507aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger
27607aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger			mod_timer(&q->timer, jiffies + PSCHED_US2JIFFIE(delay));
27707aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger			sch->flags |= TCQ_F_THROTTLED;
27807aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger		}
2790f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger	}
2800f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger
2810f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger	return NULL;
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void netem_watchdog(unsigned long arg)
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc *sch = (struct Qdisc *)arg;
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
288771018e76aaa6474be20a53c20458bcae8b00485Stephen Hemminger	pr_debug("netem_watchdog qlen=%d\n", sch->q.qlen);
289771018e76aaa6474be20a53c20458bcae8b00485Stephen Hemminger	sch->flags &= ~TCQ_F_THROTTLED;
290771018e76aaa6474be20a53c20458bcae8b00485Stephen Hemminger	netif_schedule(sch->dev);
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void netem_reset(struct Qdisc *sch)
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netem_sched_data *q = qdisc_priv(sch);
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qdisc_reset(q->qdisc);
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sch->q.qlen = 0;
299771018e76aaa6474be20a53c20458bcae8b00485Stephen Hemminger	sch->flags &= ~TCQ_F_THROTTLED;
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	del_timer_sync(&q->timer);
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int set_fifo_limit(struct Qdisc *q, int limit)
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        struct rtattr *rta;
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = -ENOMEM;
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rta = kmalloc(RTA_LENGTH(sizeof(struct tc_fifo_qopt)), GFP_KERNEL);
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rta) {
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rta->rta_type = RTM_NEWQDISC;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		rta->rta_len = RTA_LENGTH(sizeof(struct tc_fifo_qopt));
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		((struct tc_fifo_qopt *)RTA_DATA(rta))->limit = limit;
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = q->ops->change(q, rta);
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(rta);
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Distribution data is a variable size payload containing
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * signed 16 bit values.
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int get_dist_table(struct Qdisc *sch, const struct rtattr *attr)
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netem_sched_data *q = qdisc_priv(sch);
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long n = RTA_PAYLOAD(attr)/sizeof(__s16);
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const __s16 *data = RTA_DATA(attr);
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct disttable *d;
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (n > 65536)
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	d = kmalloc(sizeof(*d) + n*sizeof(d->table[0]), GFP_KERNEL);
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!d)
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	d->size = n;
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < n; i++)
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		d->table[i] = data[i];
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_bh(&sch->dev->queue_lock);
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	d = xchg(&q->delay_dist, d);
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_bh(&sch->dev->queue_lock);
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(d);
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int get_correlation(struct Qdisc *sch, const struct rtattr *attr)
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netem_sched_data *q = qdisc_priv(sch);
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const struct tc_netem_corr *c = RTA_DATA(attr);
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (RTA_PAYLOAD(attr) != sizeof(*c))
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_crandom(&q->delay_cor, c->delay_corr);
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_crandom(&q->loss_cor, c->loss_corr);
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_crandom(&q->dup_cor, c->dup_corr);
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3650dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemmingerstatic int get_reorder(struct Qdisc *sch, const struct rtattr *attr)
3660dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger{
3670dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	struct netem_sched_data *q = qdisc_priv(sch);
3680dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	const struct tc_netem_reorder *r = RTA_DATA(attr);
3690dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger
3700dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	if (RTA_PAYLOAD(attr) != sizeof(*r))
3710dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger		return -EINVAL;
3720dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger
3730dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	q->reorder = r->probability;
3740dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	init_crandom(&q->reorder_cor, r->correlation);
3750dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	return 0;
3760dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger}
3770dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int netem_change(struct Qdisc *sch, struct rtattr *opt)
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netem_sched_data *q = qdisc_priv(sch);
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tc_netem_qopt *qopt;
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (opt == NULL || RTA_PAYLOAD(opt) < sizeof(*qopt))
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qopt = RTA_DATA(opt);
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = set_fifo_limit(q->qdisc, qopt->limit);
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret) {
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pr_debug("netem: can't set fifo limit\n");
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q->latency = qopt->latency;
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q->jitter = qopt->jitter;
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q->limit = qopt->limit;
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q->gap = qopt->gap;
3980dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	q->counter = 0;
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q->loss = qopt->loss;
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q->duplicate = qopt->duplicate;
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4020dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	/* for compatiablity with earlier versions.
4030dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	 * if gap is set, need to assume 100% probablity
4040dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	 */
4050dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	q->reorder = ~0;
4060dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Handle nested options after initial queue options.
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Should have put all options in nested format but too late now.
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (RTA_PAYLOAD(opt) > sizeof(*qopt)) {
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct rtattr *tb[TCA_NETEM_MAX];
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (rtattr_parse(tb, TCA_NETEM_MAX,
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 RTA_DATA(opt) + sizeof(*qopt),
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 RTA_PAYLOAD(opt) - sizeof(*qopt)))
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tb[TCA_NETEM_CORR-1]) {
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ret = get_correlation(sch, tb[TCA_NETEM_CORR-1]);
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ret)
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return ret;
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (tb[TCA_NETEM_DELAY_DIST-1]) {
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ret = get_dist_table(sch, tb[TCA_NETEM_DELAY_DIST-1]);
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (ret)
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return ret;
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4280dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger		if (tb[TCA_NETEM_REORDER-1]) {
4290dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger			ret = get_reorder(sch, tb[TCA_NETEM_REORDER-1]);
4300dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger			if (ret)
4310dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger				return ret;
4320dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger		}
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int netem_init(struct Qdisc *sch, struct rtattr *opt)
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netem_sched_data *q = qdisc_priv(sch);
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!opt)
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_timer(&q->timer);
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q->timer.function = netem_watchdog;
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q->timer.data = (unsigned long) sch;
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q->qdisc = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops);
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!q->qdisc) {
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pr_debug("netem: qdisc create failed\n");
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = netem_change(sch, opt);
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret) {
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pr_debug("netem: change failed\n");
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qdisc_destroy(q->qdisc);
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void netem_destroy(struct Qdisc *sch)
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netem_sched_data *q = qdisc_priv(sch);
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	del_timer_sync(&q->timer);
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qdisc_destroy(q->qdisc);
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(q->delay_dist);
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int netem_dump(struct Qdisc *sch, struct sk_buff *skb)
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const struct netem_sched_data *q = qdisc_priv(sch);
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char	 *b = skb->tail;
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct rtattr *rta = (struct rtattr *) b;
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tc_netem_qopt qopt;
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tc_netem_corr cor;
4810dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	struct tc_netem_reorder reorder;
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qopt.latency = q->latency;
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qopt.jitter = q->jitter;
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qopt.limit = q->limit;
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qopt.loss = q->loss;
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qopt.gap = q->gap;
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qopt.duplicate = q->duplicate;
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	RTA_PUT(skb, TCA_OPTIONS, sizeof(qopt), &qopt);
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cor.delay_corr = q->delay_cor.rho;
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cor.loss_corr = q->loss_cor.rho;
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cor.dup_corr = q->dup_cor.rho;
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	RTA_PUT(skb, TCA_NETEM_CORR, sizeof(cor), &cor);
4950dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger
4960dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	reorder.probability = q->reorder;
4970dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	reorder.correlation = q->reorder_cor.rho;
4980dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	RTA_PUT(skb, TCA_NETEM_REORDER, sizeof(reorder), &reorder);
4990dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rta->rta_len = skb->tail - b;
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return skb->len;
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsrtattr_failure:
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_trim(skb, b - skb->data);
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int netem_dump_class(struct Qdisc *sch, unsigned long cl,
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  struct sk_buff *skb, struct tcmsg *tcm)
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netem_sched_data *q = qdisc_priv(sch);
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (cl != 1) 	/* only one class */
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOENT;
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_handle |= TC_H_MIN(1);
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tcm->tcm_info = q->qdisc->handle;
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int netem_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		     struct Qdisc **old)
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netem_sched_data *q = qdisc_priv(sch);
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (new == NULL)
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		new = &noop_qdisc;
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sch_tree_lock(sch);
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*old = xchg(&q->qdisc, new);
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qdisc_reset(*old);
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sch->q.qlen = 0;
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sch_tree_unlock(sch);
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct Qdisc *netem_leaf(struct Qdisc *sch, unsigned long arg)
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netem_sched_data *q = qdisc_priv(sch);
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return q->qdisc;
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long netem_get(struct Qdisc *sch, u32 classid)
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void netem_put(struct Qdisc *sch, unsigned long arg)
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int netem_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    struct rtattr **tca, unsigned long *arg)
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENOSYS;
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int netem_delete(struct Qdisc *sch, unsigned long arg)
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENOSYS;
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void netem_walk(struct Qdisc *sch, struct qdisc_walker *walker)
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!walker->stop) {
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (walker->count >= walker->skip)
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (walker->fn(sch, 1, walker) < 0) {
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				walker->stop = 1;
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return;
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		walker->count++;
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct tcf_proto **netem_find_tcf(struct Qdisc *sch, unsigned long cl)
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct Qdisc_class_ops netem_class_ops = {
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.graft		=	netem_graft,
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.leaf		=	netem_leaf,
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get		=	netem_get,
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.put		=	netem_put,
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.change		=	netem_change_class,
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.delete		=	netem_delete,
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.walk		=	netem_walk,
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.tcf_chain	=	netem_find_tcf,
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.dump		=	netem_dump_class,
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct Qdisc_ops netem_qdisc_ops = {
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.id		=	"netem",
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.cl_ops		=	&netem_class_ops,
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.priv_size	=	sizeof(struct netem_sched_data),
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.enqueue	=	netem_enqueue,
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.dequeue	=	netem_dequeue,
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.requeue	=	netem_requeue,
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.drop		=	netem_drop,
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.init		=	netem_init,
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.reset		=	netem_reset,
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.destroy	=	netem_destroy,
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.change		=	netem_change,
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.dump		=	netem_dump,
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner		=	THIS_MODULE,
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init netem_module_init(void)
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return register_qdisc(&netem_qdisc_ops);
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit netem_module_exit(void)
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unregister_qdisc(&netem_qdisc_ops);
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(netem_module_init)
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(netem_module_exit)
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
623