sch_netem.c revision 16bda13d90c8d5da243e2cfa1677e62ecce26860
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
7798b6b19d7a4b6e1ea5340ec8b3b92811e05b81bStephen Hemminger * 		2 of the License.
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  		Many of the algorithms and ideas for this came from
1010297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki *		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
16b7f080cfe223b3b7424872639d153695615a9255Alexey Dobriyan#include <linux/mm.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
185a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h>
2378776d3f2b2b6d59e32cdaf3f30228a0d9d0b720David S. Miller#include <linux/vmalloc.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/rtnetlink.h>
2590b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer#include <linux/reciprocal_div.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27dc5fc579b90ed0a9a4e55b0218cdbaf0a8cf2e67Arnaldo Carvalho de Melo#include <net/netlink.h>
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/pkt_sched.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30250a65f78265940ac33a2dd2002924e6126efe14stephen hemminger#define VERSION "1.3"
31eb229c4cdc3389682cda20adb015ba767950a220Stephen Hemminger
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*	Network Emulation Queuing algorithm.
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	====================================
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Sources: [1] Mark Carson, Darrin Santay, "NIST Net - A Linux-based
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 Network Emulation Tool
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 [2] Luigi Rizzo, DummyNet for FreeBSD
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 ----------------------------------------------------------------
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 This started out as a simple way to delay outgoing packets to
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 test TCP but has grown to include most of the functionality
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 of a full blown network emulator like NISTnet. It can delay
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 packets and add random jitter (and correlation). The random
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 distribution can be loaded from a table as well to provide
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 normal, Pareto, or experimental curves. Packet loss,
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 duplication, and reordering can also be emulated.
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 This qdisc does not do classification that can be handled in
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 layering other disciplines.  It does not need to do bandwidth
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 control either since that can be handled by using token
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 bucket or other rate control.
53661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
54661b79725fea030803a89a16cda506bac8eeca78stephen hemminger     Correlated Loss Generator models
55661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
56661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	Added generation of correlated loss according to the
57661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	"Gilbert-Elliot" model, a 4-state markov model.
58661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
59661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	References:
60661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	[1] NetemCLG Home http://netgroup.uniroma2.it/NetemCLG
61661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	[2] S. Salsano, F. Ludovici, A. Ordine, "Definition of a general
62661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	and intuitive loss model for packet networks and its implementation
63661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	in the Netem module in the Linux kernel", available in [1]
64661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
65661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	Authors: Stefano Salsano <stefano.salsano at uniroma2.it
66661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		 Fabio Ludovici <fabio.ludovici at yahoo.it>
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct netem_sched_data {
7050612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	/* internal t(ime)fifo qdisc uses sch->q and sch->limit */
7150612537e9ab29693122fab20fc1eed235054ffeEric Dumazet
7250612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	/* optional qdisc for classful handling (NULL at netem init) */
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc	*qdisc;
7450612537e9ab29693122fab20fc1eed235054ffeEric Dumazet
7559cb5c6734021acc68590c7c2e0e92ad9a4952c6Patrick McHardy	struct qdisc_watchdog watchdog;
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
77b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger	psched_tdiff_t latency;
78b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger	psched_tdiff_t jitter;
79b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 loss;
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 limit;
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 counter;
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 gap;
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 duplicate;
850dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	u32 reorder;
86c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger	u32 corrupt;
877bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer	u32 rate;
8890b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	s32 packet_overhead;
8990b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	u32 cell_size;
9090b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	u32 cell_size_reciprocal;
9190b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	s32 cell_overhead;
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct crndstate {
94b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger		u32 last;
95b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger		u32 rho;
96c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger	} delay_cor, loss_cor, dup_cor, reorder_cor, corrupt_cor;
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct disttable {
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u32  size;
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		s16 table[0];
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} *delay_dist;
102661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
103661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	enum  {
104661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		CLG_RANDOM,
105661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		CLG_4_STATES,
106661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		CLG_GILB_ELL,
107661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	} loss_model;
108661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
109661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	/* Correlated Loss Generation models */
110661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	struct clgstate {
111661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		/* state of the Markov chain */
112661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		u8 state;
113661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
114661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		/* 4-states and Gilbert-Elliot models */
115661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		u32 a1;	/* p13 for 4-states or p for GE */
116661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		u32 a2;	/* p31 for 4-states or r for GE */
117661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		u32 a3;	/* p32 for 4-states or h for GE */
118661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		u32 a4;	/* p14 for 4-states or 1-k for GE */
119661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		u32 a5; /* p23 used only in 4-states */
120661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	} clg;
121661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12450612537e9ab29693122fab20fc1eed235054ffeEric Dumazet/* Time stamp put into socket buffer control block
12550612537e9ab29693122fab20fc1eed235054ffeEric Dumazet * Only valid when skbs are in our internal t(ime)fifo queue.
12650612537e9ab29693122fab20fc1eed235054ffeEric Dumazet */
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct netem_skb_cb {
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psched_time_t	time_to_send;
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1315f86173bdf15981ca49d0434f638b68f70a35644Jussi Kivilinnastatic inline struct netem_skb_cb *netem_skb_cb(struct sk_buff *skb)
1325f86173bdf15981ca49d0434f638b68f70a35644Jussi Kivilinna{
13316bda13d90c8d5da243e2cfa1677e62ecce26860David S. Miller	qdisc_cb_private_validate(skb, sizeof(struct netem_skb_cb));
134175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	return (struct netem_skb_cb *)qdisc_skb_cb(skb)->data;
1355f86173bdf15981ca49d0434f638b68f70a35644Jussi Kivilinna}
1365f86173bdf15981ca49d0434f638b68f70a35644Jussi Kivilinna
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* init_crandom - initialize correlated random number generator
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Use entropy source for initial seed.
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void init_crandom(struct crndstate *state, unsigned long rho)
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	state->rho = rho;
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	state->last = net_random();
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* get_crandom - correlated random number generator
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Next number depends on last value.
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * rho is scaled to avoid floating point.
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
150b407621c35ed5f9a0734e57472e9539117963768Stephen Hemmingerstatic u32 get_crandom(struct crndstate *state)
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u64 value, rho;
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long answer;
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
155bb2f8cc0ecf025d6d3947e0389434650023f432eStephen Hemminger	if (state->rho == 0)	/* no correlation */
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return net_random();
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	value = net_random();
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rho = (u64)state->rho + 1;
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	answer = (value * ((1ull<<32) - rho) + state->last * rho) >> 32;
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	state->last = answer;
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return answer;
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
165661b79725fea030803a89a16cda506bac8eeca78stephen hemminger/* loss_4state - 4-state model loss generator
166661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * Generates losses according to the 4-state Markov chain adopted in
167661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * the GI (General and Intuitive) loss model.
168661b79725fea030803a89a16cda506bac8eeca78stephen hemminger */
169661b79725fea030803a89a16cda506bac8eeca78stephen hemmingerstatic bool loss_4state(struct netem_sched_data *q)
170661b79725fea030803a89a16cda506bac8eeca78stephen hemminger{
171661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	struct clgstate *clg = &q->clg;
172661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	u32 rnd = net_random();
173661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
174661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	/*
17525985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	 * Makes a comparison between rnd and the transition
176661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	 * probabilities outgoing from the current state, then decides the
177661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	 * next state and if the next packet has to be transmitted or lost.
178661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	 * The four states correspond to:
179661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	 *   1 => successfully transmitted packets within a gap period
180661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	 *   4 => isolated losses within a gap period
181661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	 *   3 => lost packets within a burst period
182661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	 *   2 => successfully transmitted packets within a burst period
183661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	 */
184661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	switch (clg->state) {
185661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	case 1:
186661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		if (rnd < clg->a4) {
187661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			clg->state = 4;
188661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			return true;
189661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		} else if (clg->a4 < rnd && rnd < clg->a1) {
190661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			clg->state = 3;
191661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			return true;
192661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		} else if (clg->a1 < rnd)
193661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			clg->state = 1;
194661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
195661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		break;
196661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	case 2:
197661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		if (rnd < clg->a5) {
198661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			clg->state = 3;
199661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			return true;
200661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		} else
201661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			clg->state = 2;
202661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
203661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		break;
204661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	case 3:
205661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		if (rnd < clg->a3)
206661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			clg->state = 2;
207661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		else if (clg->a3 < rnd && rnd < clg->a2 + clg->a3) {
208661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			clg->state = 1;
209661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			return true;
210661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		} else if (clg->a2 + clg->a3 < rnd) {
211661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			clg->state = 3;
212661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			return true;
213661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		}
214661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		break;
215661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	case 4:
216661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		clg->state = 1;
217661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		break;
218661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	}
219661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
220661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	return false;
221661b79725fea030803a89a16cda506bac8eeca78stephen hemminger}
222661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
223661b79725fea030803a89a16cda506bac8eeca78stephen hemminger/* loss_gilb_ell - Gilbert-Elliot model loss generator
224661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * Generates losses according to the Gilbert-Elliot loss model or
225661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * its special cases  (Gilbert or Simple Gilbert)
226661b79725fea030803a89a16cda506bac8eeca78stephen hemminger *
22725985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * Makes a comparison between random number and the transition
228661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * probabilities outgoing from the current state, then decides the
22925985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * next state. A second random number is extracted and the comparison
230661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * with the loss probability of the current state decides if the next
231661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * packet will be transmitted or lost.
232661b79725fea030803a89a16cda506bac8eeca78stephen hemminger */
233661b79725fea030803a89a16cda506bac8eeca78stephen hemmingerstatic bool loss_gilb_ell(struct netem_sched_data *q)
234661b79725fea030803a89a16cda506bac8eeca78stephen hemminger{
235661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	struct clgstate *clg = &q->clg;
236661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
237661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	switch (clg->state) {
238661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	case 1:
239661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		if (net_random() < clg->a1)
240661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			clg->state = 2;
241661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		if (net_random() < clg->a4)
242661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			return true;
243661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	case 2:
244661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		if (net_random() < clg->a2)
245661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			clg->state = 1;
246661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		if (clg->a3 > net_random())
247661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			return true;
248661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	}
249661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
250661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	return false;
251661b79725fea030803a89a16cda506bac8eeca78stephen hemminger}
252661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
253661b79725fea030803a89a16cda506bac8eeca78stephen hemmingerstatic bool loss_event(struct netem_sched_data *q)
254661b79725fea030803a89a16cda506bac8eeca78stephen hemminger{
255661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	switch (q->loss_model) {
256661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	case CLG_RANDOM:
257661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		/* Random packet drop 0 => none, ~0 => all */
258661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		return q->loss && q->loss >= get_crandom(&q->loss_cor);
259661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
260661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	case CLG_4_STATES:
261661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		/* 4state loss model algorithm (used also for GI model)
262661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		* Extracts a value from the markov 4 state loss generator,
263661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		* if it is 1 drops a packet and if needed writes the event in
264661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		* the kernel logs
265661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		*/
266661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		return loss_4state(q);
267661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
268661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	case CLG_GILB_ELL:
269661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		/* Gilbert-Elliot loss model algorithm
270661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		* Extracts a value from the Gilbert-Elliot loss generator,
271661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		* if it is 1 drops a packet and if needed writes the event in
272661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		* the kernel logs
273661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		*/
274661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		return loss_gilb_ell(q);
275661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	}
276661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
277661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	return false;	/* not reached */
278661b79725fea030803a89a16cda506bac8eeca78stephen hemminger}
279661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
280661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* tabledist - return a pseudo-randomly distributed value with mean mu and
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * std deviation sigma.  Uses table lookup to approximate the desired
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * distribution, and a uniformly-distributed pseudo-random source.
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
285b407621c35ed5f9a0734e57472e9539117963768Stephen Hemmingerstatic psched_tdiff_t tabledist(psched_tdiff_t mu, psched_tdiff_t sigma,
286b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger				struct crndstate *state,
287b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger				const struct disttable *dist)
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
289b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger	psched_tdiff_t x;
290b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger	long t;
291b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger	u32 rnd;
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sigma == 0)
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return mu;
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rnd = get_crandom(state);
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* default uniform distribution */
29910297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki	if (dist == NULL)
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (rnd % (2*sigma)) - sigma + mu;
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	t = dist->table[rnd % dist->size];
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	x = (sigma % NETEM_DIST_SCALE) * t;
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (x >= 0)
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		x += NETEM_DIST_SCALE/2;
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		x -= NETEM_DIST_SCALE/2;
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return  x / NETEM_DIST_SCALE + (sigma / NETEM_DIST_SCALE) * t + mu;
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31290b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeiferstatic psched_time_t packet_len_2_sched_time(unsigned int len, struct netem_sched_data *q)
3137bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer{
31490b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	u64 ticks;
315fc33cc72423ed3474cd51bc8bd7c1cdc22a78e1aEric Dumazet
31690b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	len += q->packet_overhead;
31790b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer
31890b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	if (q->cell_size) {
31990b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer		u32 cells = reciprocal_divide(len, q->cell_size_reciprocal);
32090b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer
32190b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer		if (len > cells * q->cell_size)	/* extra cell needed for remainder */
32290b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer			cells++;
32390b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer		len = cells * (q->cell_size + q->cell_overhead);
32490b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	}
32590b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer
32690b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	ticks = (u64)len * NSEC_PER_SEC;
32790b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer
32890b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	do_div(ticks, q->rate);
329fc33cc72423ed3474cd51bc8bd7c1cdc22a78e1aEric Dumazet	return PSCHED_NS2TICKS(ticks);
3307bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer}
3317bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer
33250612537e9ab29693122fab20fc1eed235054ffeEric Dumazetstatic int tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch)
33350612537e9ab29693122fab20fc1eed235054ffeEric Dumazet{
33450612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	struct sk_buff_head *list = &sch->q;
33550612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	psched_time_t tnext = netem_skb_cb(nskb)->time_to_send;
33650612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	struct sk_buff *skb;
33750612537e9ab29693122fab20fc1eed235054ffeEric Dumazet
33850612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	if (likely(skb_queue_len(list) < sch->limit)) {
33950612537e9ab29693122fab20fc1eed235054ffeEric Dumazet		skb = skb_peek_tail(list);
34050612537e9ab29693122fab20fc1eed235054ffeEric Dumazet		/* Optimize for add at tail */
34150612537e9ab29693122fab20fc1eed235054ffeEric Dumazet		if (likely(!skb || tnext >= netem_skb_cb(skb)->time_to_send))
34250612537e9ab29693122fab20fc1eed235054ffeEric Dumazet			return qdisc_enqueue_tail(nskb, sch);
34350612537e9ab29693122fab20fc1eed235054ffeEric Dumazet
34450612537e9ab29693122fab20fc1eed235054ffeEric Dumazet		skb_queue_reverse_walk(list, skb) {
34550612537e9ab29693122fab20fc1eed235054ffeEric Dumazet			if (tnext >= netem_skb_cb(skb)->time_to_send)
34650612537e9ab29693122fab20fc1eed235054ffeEric Dumazet				break;
34750612537e9ab29693122fab20fc1eed235054ffeEric Dumazet		}
34850612537e9ab29693122fab20fc1eed235054ffeEric Dumazet
34950612537e9ab29693122fab20fc1eed235054ffeEric Dumazet		__skb_queue_after(list, skb, nskb);
35050612537e9ab29693122fab20fc1eed235054ffeEric Dumazet		sch->qstats.backlog += qdisc_pkt_len(nskb);
35150612537e9ab29693122fab20fc1eed235054ffeEric Dumazet		return NET_XMIT_SUCCESS;
35250612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	}
35350612537e9ab29693122fab20fc1eed235054ffeEric Dumazet
35450612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	return qdisc_reshape_fail(nskb, sch);
35550612537e9ab29693122fab20fc1eed235054ffeEric Dumazet}
35650612537e9ab29693122fab20fc1eed235054ffeEric Dumazet
3570afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger/*
3580afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger * Insert one skb into qdisc.
3590afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger * Note: parent depends on return value to account for queue length.
3600afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger * 	NET_XMIT_DROP: queue length didn't change.
3610afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger *      NET_XMIT_SUCCESS: one skb was queued.
3620afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger */
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netem_sched_data *q = qdisc_priv(sch);
36689e1df74f841fc31e81838d30594c4eff01859f8Guillaume Chazarain	/* We don't fill cb now as skb_unshare() may invalidate it */
36789e1df74f841fc31e81838d30594c4eff01859f8Guillaume Chazarain	struct netem_skb_cb *cb;
3680afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	struct sk_buff *skb2;
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
3700afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	int count = 1;
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3720afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	/* Random duplication */
3730afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	if (q->duplicate && q->duplicate >= get_crandom(&q->dup_cor))
3740afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger		++count;
3750afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger
376661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	/* Drop packet? */
377661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	if (loss_event(q))
3780afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger		--count;
3790afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger
3800afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	if (count == 0) {
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sch->qstats.drops++;
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree_skb(skb);
383c27f339af90bb874a7a9c680b17abfd32d4a727bJarek Poplawski		return NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3864e8a5201506423e0241202de1349422af4260296David S. Miller	skb_orphan(skb);
3874e8a5201506423e0241202de1349422af4260296David S. Miller
3880afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	/*
3890afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	 * If we need to duplicate packet, then re-insert at top of the
3900afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	 * qdisc tree, since parent queuer expects that only one
3910afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	 * skb will be queued.
3920afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	 */
3930afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	if (count > 1 && (skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) {
3947698b4fcabcd790efc4f226bada1e7b5870653afDavid S. Miller		struct Qdisc *rootq = qdisc_root(sch);
3950afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger		u32 dupsave = q->duplicate; /* prevent duplicating a dup... */
3960afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger		q->duplicate = 0;
3970afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger
3985f86173bdf15981ca49d0434f638b68f70a35644Jussi Kivilinna		qdisc_enqueue_root(skb2, rootq);
3990afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger		q->duplicate = dupsave;
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
402c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger	/*
403c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger	 * Randomized packet corruption.
404c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger	 * Make copy if needed since we are modifying
405c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger	 * If packet is going to be hardware checksummed, then
406c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger	 * do it now in software before we mangle it.
407c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger	 */
408c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger	if (q->corrupt && q->corrupt >= get_crandom(&q->corrupt_cor)) {
409f64f9e719261a87818dd192a3a2352e5b20fbd0fJoe Perches		if (!(skb = skb_unshare(skb, GFP_ATOMIC)) ||
410f64f9e719261a87818dd192a3a2352e5b20fbd0fJoe Perches		    (skb->ip_summed == CHECKSUM_PARTIAL &&
411f64f9e719261a87818dd192a3a2352e5b20fbd0fJoe Perches		     skb_checksum_help(skb))) {
412c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger			sch->qstats.drops++;
413c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger			return NET_XMIT_DROP;
414c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger		}
415c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger
416c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger		skb->data[net_random() % skb_headlen(skb)] ^= 1<<(net_random() % 8);
417c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger	}
418c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger
4195f86173bdf15981ca49d0434f638b68f70a35644Jussi Kivilinna	cb = netem_skb_cb(skb);
420cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet	if (q->gap == 0 ||		/* not doing reordering */
421a42b4799c683723e8c464de4026af085b2ebd5faVijay Subramanian	    q->counter < q->gap - 1 ||	/* inside last reordering gap */
422f64f9e719261a87818dd192a3a2352e5b20fbd0fJoe Perches	    q->reorder < get_crandom(&q->reorder_cor)) {
4230f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger		psched_time_t now;
42407aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger		psched_tdiff_t delay;
42507aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger
42607aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger		delay = tabledist(q->latency, q->jitter,
42707aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger				  &q->delay_cor, q->delay_dist);
42807aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger
4293bebcda28077375470dd60545b71bba2f83335fdPatrick McHardy		now = psched_get_time();
4307bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer
4317bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer		if (q->rate) {
43250612537e9ab29693122fab20fc1eed235054ffeEric Dumazet			struct sk_buff_head *list = &sch->q;
4337bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer
43490b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer			delay += packet_len_2_sched_time(skb->len, q);
4357bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer
4367bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer			if (!skb_queue_empty(list)) {
4377bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer				/*
4387bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer				 * Last packet in queue is reference point (now).
4397bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer				 * First packet in queue is already in flight,
4407bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer				 * calculate this time bonus and substract
4417bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer				 * from delay.
4427bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer				 */
4437bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer				delay -= now - netem_skb_cb(skb_peek(list))->time_to_send;
4447bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer				now = netem_skb_cb(skb_peek_tail(list))->time_to_send;
4457bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer			}
4467bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer		}
4477bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer
4487c59e25f3186f26e85b13a318dbc4482d1d363e9Patrick McHardy		cb->time_to_send = now + delay;
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		++q->counter;
45050612537e9ab29693122fab20fc1eed235054ffeEric Dumazet		ret = tfifo_enqueue(skb, sch);
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
45210297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki		/*
4530dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger		 * Do re-ordering by putting one out of N packets at the front
4540dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger		 * of the queue.
4550dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger		 */
4563bebcda28077375470dd60545b71bba2f83335fdPatrick McHardy		cb->time_to_send = psched_get_time();
4570dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger		q->counter = 0;
4588ba25dad0ac78850cd46d91186a27d60f7314752Jarek Poplawski
45950612537e9ab29693122fab20fc1eed235054ffeEric Dumazet		__skb_queue_head(&sch->q, skb);
460eb10192447370f19a215a8c2749332afa1199d46Hagen Paul Pfeifer		sch->qstats.backlog += qdisc_pkt_len(skb);
461eb10192447370f19a215a8c2749332afa1199d46Hagen Paul Pfeifer		sch->qstats.requeues++;
4628ba25dad0ac78850cd46d91186a27d60f7314752Jarek Poplawski		ret = NET_XMIT_SUCCESS;
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46510f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	if (ret != NET_XMIT_SUCCESS) {
46610f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger		if (net_xmit_drop_count(ret)) {
46710f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger			sch->qstats.drops++;
46810f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger			return ret;
46910f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger		}
470378a2f090f7a478704a372a4869b8a9ac206234eJarek Poplawski	}
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47210f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	return NET_XMIT_SUCCESS;
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
475cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazetstatic unsigned int netem_drop(struct Qdisc *sch)
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netem_sched_data *q = qdisc_priv(sch);
47850612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	unsigned int len;
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
48050612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	len = qdisc_queue_drop(sch);
48150612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	if (!len && q->qdisc && q->qdisc->ops->drop)
48250612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	    len = q->qdisc->ops->drop(q->qdisc);
48350612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	if (len)
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sch->qstats.drops++;
48550612537e9ab29693122fab20fc1eed235054ffeEric Dumazet
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return len;
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sk_buff *netem_dequeue(struct Qdisc *sch)
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netem_sched_data *q = qdisc_priv(sch);
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
494fd245a4adb5288eac37250875f237c40a20a1944Eric Dumazet	if (qdisc_is_throttled(sch))
49511274e5a43266d531140530adebead6903380cafStephen Hemminger		return NULL;
49611274e5a43266d531140530adebead6903380cafStephen Hemminger
49750612537e9ab29693122fab20fc1eed235054ffeEric Dumazettfifo_dequeue:
49850612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	skb = qdisc_peek_head(sch);
499771018e76aaa6474be20a53c20458bcae8b00485Stephen Hemminger	if (skb) {
5005f86173bdf15981ca49d0434f638b68f70a35644Jussi Kivilinna		const struct netem_skb_cb *cb = netem_skb_cb(skb);
5010f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger
5020f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger		/* if more time remaining? */
50350612537e9ab29693122fab20fc1eed235054ffeEric Dumazet		if (cb->time_to_send <= psched_get_time()) {
50450612537e9ab29693122fab20fc1eed235054ffeEric Dumazet			skb = qdisc_dequeue_tail(sch);
50577be155cba4e163e8bba9fd27222a8b6189ec4f7Jarek Poplawski			if (unlikely(!skb))
50650612537e9ab29693122fab20fc1eed235054ffeEric Dumazet				goto qdisc_dequeue;
50703c05f0d4bb0c267edf12d614025a40e33c5a6f9Jarek Poplawski
5088caf153974f2274301e583fda732cc8e5b80331fJarek Poplawski#ifdef CONFIG_NET_CLS_ACT
5098caf153974f2274301e583fda732cc8e5b80331fJarek Poplawski			/*
5108caf153974f2274301e583fda732cc8e5b80331fJarek Poplawski			 * If it's at ingress let's pretend the delay is
5118caf153974f2274301e583fda732cc8e5b80331fJarek Poplawski			 * from the network (tstamp will be updated).
5128caf153974f2274301e583fda732cc8e5b80331fJarek Poplawski			 */
5138caf153974f2274301e583fda732cc8e5b80331fJarek Poplawski			if (G_TC_FROM(skb->tc_verd) & AT_INGRESS)
5148caf153974f2274301e583fda732cc8e5b80331fJarek Poplawski				skb->tstamp.tv64 = 0;
5158caf153974f2274301e583fda732cc8e5b80331fJarek Poplawski#endif
51610f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger
51750612537e9ab29693122fab20fc1eed235054ffeEric Dumazet			if (q->qdisc) {
51850612537e9ab29693122fab20fc1eed235054ffeEric Dumazet				int err = qdisc_enqueue(skb, q->qdisc);
51950612537e9ab29693122fab20fc1eed235054ffeEric Dumazet
52050612537e9ab29693122fab20fc1eed235054ffeEric Dumazet				if (unlikely(err != NET_XMIT_SUCCESS)) {
52150612537e9ab29693122fab20fc1eed235054ffeEric Dumazet					if (net_xmit_drop_count(err)) {
52250612537e9ab29693122fab20fc1eed235054ffeEric Dumazet						sch->qstats.drops++;
52350612537e9ab29693122fab20fc1eed235054ffeEric Dumazet						qdisc_tree_decrease_qlen(sch, 1);
52450612537e9ab29693122fab20fc1eed235054ffeEric Dumazet					}
52550612537e9ab29693122fab20fc1eed235054ffeEric Dumazet				}
52650612537e9ab29693122fab20fc1eed235054ffeEric Dumazet				goto tfifo_dequeue;
52750612537e9ab29693122fab20fc1eed235054ffeEric Dumazet			}
52850612537e9ab29693122fab20fc1eed235054ffeEric Dumazetdeliver:
52910f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger			qdisc_unthrottled(sch);
53010f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger			qdisc_bstats_update(sch, skb);
5310f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger			return skb;
53207aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger		}
53311274e5a43266d531140530adebead6903380cafStephen Hemminger
53450612537e9ab29693122fab20fc1eed235054ffeEric Dumazet		if (q->qdisc) {
53550612537e9ab29693122fab20fc1eed235054ffeEric Dumazet			skb = q->qdisc->ops->dequeue(q->qdisc);
53650612537e9ab29693122fab20fc1eed235054ffeEric Dumazet			if (skb)
53750612537e9ab29693122fab20fc1eed235054ffeEric Dumazet				goto deliver;
53850612537e9ab29693122fab20fc1eed235054ffeEric Dumazet		}
53911274e5a43266d531140530adebead6903380cafStephen Hemminger		qdisc_watchdog_schedule(&q->watchdog, cb->time_to_send);
5400f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger	}
5410f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger
54250612537e9ab29693122fab20fc1eed235054ffeEric Dumazetqdisc_dequeue:
54350612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	if (q->qdisc) {
54450612537e9ab29693122fab20fc1eed235054ffeEric Dumazet		skb = q->qdisc->ops->dequeue(q->qdisc);
54550612537e9ab29693122fab20fc1eed235054ffeEric Dumazet		if (skb)
54650612537e9ab29693122fab20fc1eed235054ffeEric Dumazet			goto deliver;
54750612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	}
5480f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger	return NULL;
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void netem_reset(struct Qdisc *sch)
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netem_sched_data *q = qdisc_priv(sch);
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
55550612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	qdisc_reset_queue(sch);
55650612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	if (q->qdisc)
55750612537e9ab29693122fab20fc1eed235054ffeEric Dumazet		qdisc_reset(q->qdisc);
55859cb5c6734021acc68590c7c2e0e92ad9a4952c6Patrick McHardy	qdisc_watchdog_cancel(&q->watchdog);
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5616373a9a286bdd955a76924cee88a2f8f784988b1stephen hemmingerstatic void dist_free(struct disttable *d)
5626373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger{
5636373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger	if (d) {
5646373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger		if (is_vmalloc_addr(d))
5656373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger			vfree(d);
5666373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger		else
5676373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger			kfree(d);
5686373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger	}
5696373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger}
5706373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Distribution data is a variable size payload containing
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * signed 16 bit values.
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5751e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardystatic int get_dist_table(struct Qdisc *sch, const struct nlattr *attr)
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netem_sched_data *q = qdisc_priv(sch);
5786373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger	size_t n = nla_len(attr)/sizeof(__s16);
5791e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	const __s16 *data = nla_data(attr);
5807698b4fcabcd790efc4f226bada1e7b5870653afDavid S. Miller	spinlock_t *root_lock;
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct disttable *d;
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
5836373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger	size_t s;
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
585df173bda2639ac744ccf596ec1f8f7e66fe4c343stephen hemminger	if (n > NETEM_DIST_MAX)
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5886373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger	s = sizeof(struct disttable) + n * sizeof(s16);
589bb52c7acf871537a468433775151339f783d2e8cEric Dumazet	d = kmalloc(s, GFP_KERNEL | __GFP_NOWARN);
5906373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger	if (!d)
5916373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger		d = vmalloc(s);
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!d)
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	d->size = n;
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < n; i++)
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		d->table[i] = data[i];
59810297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki
599102396ae65108b026e4e1868e30fa013f45a169eJarek Poplawski	root_lock = qdisc_root_sleeping_lock(sch);
6007698b4fcabcd790efc4f226bada1e7b5870653afDavid S. Miller
6017698b4fcabcd790efc4f226bada1e7b5870653afDavid S. Miller	spin_lock_bh(root_lock);
602bb52c7acf871537a468433775151339f783d2e8cEric Dumazet	swap(q->delay_dist, d);
6037698b4fcabcd790efc4f226bada1e7b5870653afDavid S. Miller	spin_unlock_bh(root_lock);
604bb52c7acf871537a468433775151339f783d2e8cEric Dumazet
605bb52c7acf871537a468433775151339f783d2e8cEric Dumazet	dist_free(d);
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
609265eb67fb4e16be8e46a51e1e4e2ecd99fb15219Stephen Hemmingerstatic void get_correlation(struct Qdisc *sch, const struct nlattr *attr)
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netem_sched_data *q = qdisc_priv(sch);
6121e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	const struct tc_netem_corr *c = nla_data(attr);
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_crandom(&q->delay_cor, c->delay_corr);
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_crandom(&q->loss_cor, c->loss_corr);
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_crandom(&q->dup_cor, c->dup_corr);
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
619265eb67fb4e16be8e46a51e1e4e2ecd99fb15219Stephen Hemmingerstatic void get_reorder(struct Qdisc *sch, const struct nlattr *attr)
6200dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger{
6210dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	struct netem_sched_data *q = qdisc_priv(sch);
6221e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	const struct tc_netem_reorder *r = nla_data(attr);
6230dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger
6240dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	q->reorder = r->probability;
6250dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	init_crandom(&q->reorder_cor, r->correlation);
6260dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger}
6270dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger
628265eb67fb4e16be8e46a51e1e4e2ecd99fb15219Stephen Hemmingerstatic void get_corrupt(struct Qdisc *sch, const struct nlattr *attr)
629c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger{
630c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger	struct netem_sched_data *q = qdisc_priv(sch);
6311e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	const struct tc_netem_corrupt *r = nla_data(attr);
632c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger
633c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger	q->corrupt = r->probability;
634c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger	init_crandom(&q->corrupt_cor, r->correlation);
635c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger}
636c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger
6377bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeiferstatic void get_rate(struct Qdisc *sch, const struct nlattr *attr)
6387bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer{
6397bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer	struct netem_sched_data *q = qdisc_priv(sch);
6407bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer	const struct tc_netem_rate *r = nla_data(attr);
6417bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer
6427bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer	q->rate = r->rate;
64390b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	q->packet_overhead = r->packet_overhead;
64490b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	q->cell_size = r->cell_size;
64590b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	if (q->cell_size)
64690b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer		q->cell_size_reciprocal = reciprocal_value(q->cell_size);
64790b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	q->cell_overhead = r->cell_overhead;
6487bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer}
6497bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer
650661b79725fea030803a89a16cda506bac8eeca78stephen hemmingerstatic int get_loss_clg(struct Qdisc *sch, const struct nlattr *attr)
651661b79725fea030803a89a16cda506bac8eeca78stephen hemminger{
652661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	struct netem_sched_data *q = qdisc_priv(sch);
653661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	const struct nlattr *la;
654661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	int rem;
655661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
656661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	nla_for_each_nested(la, attr, rem) {
657661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		u16 type = nla_type(la);
658661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
659661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		switch(type) {
660661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		case NETEM_LOSS_GI: {
661661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			const struct tc_netem_gimodel *gi = nla_data(la);
662661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
6632494654d4890316e7340fb8b3458daad0474a1b9stephen hemminger			if (nla_len(la) < sizeof(struct tc_netem_gimodel)) {
664661b79725fea030803a89a16cda506bac8eeca78stephen hemminger				pr_info("netem: incorrect gi model size\n");
665661b79725fea030803a89a16cda506bac8eeca78stephen hemminger				return -EINVAL;
666661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			}
667661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
668661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			q->loss_model = CLG_4_STATES;
669661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
670661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			q->clg.state = 1;
671661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			q->clg.a1 = gi->p13;
672661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			q->clg.a2 = gi->p31;
673661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			q->clg.a3 = gi->p32;
674661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			q->clg.a4 = gi->p14;
675661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			q->clg.a5 = gi->p23;
676661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			break;
677661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		}
678661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
679661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		case NETEM_LOSS_GE: {
680661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			const struct tc_netem_gemodel *ge = nla_data(la);
681661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
6822494654d4890316e7340fb8b3458daad0474a1b9stephen hemminger			if (nla_len(la) < sizeof(struct tc_netem_gemodel)) {
6832494654d4890316e7340fb8b3458daad0474a1b9stephen hemminger				pr_info("netem: incorrect ge model size\n");
684661b79725fea030803a89a16cda506bac8eeca78stephen hemminger				return -EINVAL;
685661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			}
686661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
687661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			q->loss_model = CLG_GILB_ELL;
688661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			q->clg.state = 1;
689661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			q->clg.a1 = ge->p;
690661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			q->clg.a2 = ge->r;
691661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			q->clg.a3 = ge->h;
692661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			q->clg.a4 = ge->k1;
693661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			break;
694661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		}
695661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
696661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		default:
697661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			pr_info("netem: unknown loss type %u\n", type);
698661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			return -EINVAL;
699661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		}
700661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	}
701661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
702661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	return 0;
703661b79725fea030803a89a16cda506bac8eeca78stephen hemminger}
704661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
70527a3421e4821734bc19496faa77b380605dc3b23Patrick McHardystatic const struct nla_policy netem_policy[TCA_NETEM_MAX + 1] = {
70627a3421e4821734bc19496faa77b380605dc3b23Patrick McHardy	[TCA_NETEM_CORR]	= { .len = sizeof(struct tc_netem_corr) },
70727a3421e4821734bc19496faa77b380605dc3b23Patrick McHardy	[TCA_NETEM_REORDER]	= { .len = sizeof(struct tc_netem_reorder) },
70827a3421e4821734bc19496faa77b380605dc3b23Patrick McHardy	[TCA_NETEM_CORRUPT]	= { .len = sizeof(struct tc_netem_corrupt) },
7097bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer	[TCA_NETEM_RATE]	= { .len = sizeof(struct tc_netem_rate) },
710661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	[TCA_NETEM_LOSS]	= { .type = NLA_NESTED },
71127a3421e4821734bc19496faa77b380605dc3b23Patrick McHardy};
71227a3421e4821734bc19496faa77b380605dc3b23Patrick McHardy
7132c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Grafstatic int parse_attr(struct nlattr *tb[], int maxtype, struct nlattr *nla,
7142c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf		      const struct nla_policy *policy, int len)
7152c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf{
7162c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf	int nested_len = nla_len(nla) - NLA_ALIGN(len);
7172c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf
718661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	if (nested_len < 0) {
719661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		pr_info("netem: invalid attributes len %d\n", nested_len);
7202c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf		return -EINVAL;
721661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	}
722661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
7232c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf	if (nested_len >= nla_attr_size(0))
7242c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf		return nla_parse(tb, maxtype, nla_data(nla) + NLA_ALIGN(len),
7252c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf				 nested_len, policy);
726661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
7272c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf	memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
7282c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf	return 0;
7292c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf}
7302c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf
731c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger/* Parse netlink message to set options */
7321e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardystatic int netem_change(struct Qdisc *sch, struct nlattr *opt)
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netem_sched_data *q = qdisc_priv(sch);
735b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy	struct nlattr *tb[TCA_NETEM_MAX + 1];
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tc_netem_qopt *qopt;
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
73810297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki
739b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy	if (opt == NULL)
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7422c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf	qopt = nla_data(opt);
7432c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf	ret = parse_attr(tb, TCA_NETEM_MAX, opt, netem_policy, sizeof(*qopt));
744b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy	if (ret < 0)
745b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy		return ret;
746b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy
74750612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	sch->limit = qopt->limit;
74810297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q->latency = qopt->latency;
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q->jitter = qopt->jitter;
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q->limit = qopt->limit;
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q->gap = qopt->gap;
7530dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	q->counter = 0;
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q->loss = qopt->loss;
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q->duplicate = qopt->duplicate;
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
757bb2f8cc0ecf025d6d3947e0389434650023f432eStephen Hemminger	/* for compatibility with earlier versions.
758bb2f8cc0ecf025d6d3947e0389434650023f432eStephen Hemminger	 * if gap is set, need to assume 100% probability
7590dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	 */
760a362e0a7890c735a3ef63aab12d71ecfc6e6f4a5Stephen Hemminger	if (q->gap)
761a362e0a7890c735a3ef63aab12d71ecfc6e6f4a5Stephen Hemminger		q->reorder = ~0;
7620dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger
763265eb67fb4e16be8e46a51e1e4e2ecd99fb15219Stephen Hemminger	if (tb[TCA_NETEM_CORR])
764265eb67fb4e16be8e46a51e1e4e2ecd99fb15219Stephen Hemminger		get_correlation(sch, tb[TCA_NETEM_CORR]);
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
766b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy	if (tb[TCA_NETEM_DELAY_DIST]) {
767b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy		ret = get_dist_table(sch, tb[TCA_NETEM_DELAY_DIST]);
768b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy		if (ret)
769b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy			return ret;
770b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy	}
771c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger
772265eb67fb4e16be8e46a51e1e4e2ecd99fb15219Stephen Hemminger	if (tb[TCA_NETEM_REORDER])
773265eb67fb4e16be8e46a51e1e4e2ecd99fb15219Stephen Hemminger		get_reorder(sch, tb[TCA_NETEM_REORDER]);
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
775265eb67fb4e16be8e46a51e1e4e2ecd99fb15219Stephen Hemminger	if (tb[TCA_NETEM_CORRUPT])
776265eb67fb4e16be8e46a51e1e4e2ecd99fb15219Stephen Hemminger		get_corrupt(sch, tb[TCA_NETEM_CORRUPT]);
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7787bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer	if (tb[TCA_NETEM_RATE])
7797bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer		get_rate(sch, tb[TCA_NETEM_RATE]);
7807bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer
781661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	q->loss_model = CLG_RANDOM;
782661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	if (tb[TCA_NETEM_LOSS])
783661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		ret = get_loss_clg(sch, tb[TCA_NETEM_LOSS]);
784661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
785661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	return ret;
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7881e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardystatic int netem_init(struct Qdisc *sch, struct nlattr *opt)
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netem_sched_data *q = qdisc_priv(sch);
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!opt)
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
79659cb5c6734021acc68590c7c2e0e92ad9a4952c6Patrick McHardy	qdisc_watchdog_init(&q->watchdog, sch);
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
798661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	q->loss_model = CLG_RANDOM;
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = netem_change(sch, opt);
80050612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	if (ret)
801250a65f78265940ac33a2dd2002924e6126efe14stephen hemminger		pr_info("netem: change failed\n");
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void netem_destroy(struct Qdisc *sch)
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netem_sched_data *q = qdisc_priv(sch);
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
80959cb5c6734021acc68590c7c2e0e92ad9a4952c6Patrick McHardy	qdisc_watchdog_cancel(&q->watchdog);
81050612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	if (q->qdisc)
81150612537e9ab29693122fab20fc1eed235054ffeEric Dumazet		qdisc_destroy(q->qdisc);
8126373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger	dist_free(q->delay_dist);
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
815661b79725fea030803a89a16cda506bac8eeca78stephen hemmingerstatic int dump_loss_model(const struct netem_sched_data *q,
816661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			   struct sk_buff *skb)
817661b79725fea030803a89a16cda506bac8eeca78stephen hemminger{
818661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	struct nlattr *nest;
819661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
820661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	nest = nla_nest_start(skb, TCA_NETEM_LOSS);
821661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	if (nest == NULL)
822661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		goto nla_put_failure;
823661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
824661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	switch (q->loss_model) {
825661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	case CLG_RANDOM:
826661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		/* legacy loss model */
827661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		nla_nest_cancel(skb, nest);
828661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		return 0;	/* no data */
829661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
830661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	case CLG_4_STATES: {
831661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		struct tc_netem_gimodel gi = {
832661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			.p13 = q->clg.a1,
833661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			.p31 = q->clg.a2,
834661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			.p32 = q->clg.a3,
835661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			.p14 = q->clg.a4,
836661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			.p23 = q->clg.a5,
837661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		};
838661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
839661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		NLA_PUT(skb, NETEM_LOSS_GI, sizeof(gi), &gi);
840661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		break;
841661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	}
842661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	case CLG_GILB_ELL: {
843661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		struct tc_netem_gemodel ge = {
844661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			.p = q->clg.a1,
845661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			.r = q->clg.a2,
846661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			.h = q->clg.a3,
847661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			.k1 = q->clg.a4,
848661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		};
849661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
850661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		NLA_PUT(skb, NETEM_LOSS_GE, sizeof(ge), &ge);
851661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		break;
852661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	}
853661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	}
854661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
855661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	nla_nest_end(skb, nest);
856661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	return 0;
857661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
858661b79725fea030803a89a16cda506bac8eeca78stephen hemmingernla_put_failure:
859661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	nla_nest_cancel(skb, nest);
860661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	return -1;
861661b79725fea030803a89a16cda506bac8eeca78stephen hemminger}
862661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int netem_dump(struct Qdisc *sch, struct sk_buff *skb)
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const struct netem_sched_data *q = qdisc_priv(sch);
866861d7f745f37506bbd90227e97b95baf2a5fac34stephen hemminger	struct nlattr *nla = (struct nlattr *) skb_tail_pointer(skb);
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tc_netem_qopt qopt;
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tc_netem_corr cor;
8690dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	struct tc_netem_reorder reorder;
870c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger	struct tc_netem_corrupt corrupt;
8717bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer	struct tc_netem_rate rate;
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qopt.latency = q->latency;
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qopt.jitter = q->jitter;
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qopt.limit = q->limit;
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qopt.loss = q->loss;
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qopt.gap = q->gap;
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qopt.duplicate = q->duplicate;
8791e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	NLA_PUT(skb, TCA_OPTIONS, sizeof(qopt), &qopt);
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cor.delay_corr = q->delay_cor.rho;
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cor.loss_corr = q->loss_cor.rho;
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cor.dup_corr = q->dup_cor.rho;
8841e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	NLA_PUT(skb, TCA_NETEM_CORR, sizeof(cor), &cor);
8850dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger
8860dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	reorder.probability = q->reorder;
8870dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	reorder.correlation = q->reorder_cor.rho;
8881e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	NLA_PUT(skb, TCA_NETEM_REORDER, sizeof(reorder), &reorder);
8890dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger
890c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger	corrupt.probability = q->corrupt;
891c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger	corrupt.correlation = q->corrupt_cor.rho;
8921e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	NLA_PUT(skb, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt);
893c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger
8947bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer	rate.rate = q->rate;
89590b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	rate.packet_overhead = q->packet_overhead;
89690b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	rate.cell_size = q->cell_size;
89790b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	rate.cell_overhead = q->cell_overhead;
8987bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer	NLA_PUT(skb, TCA_NETEM_RATE, sizeof(rate), &rate);
8997bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer
900661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	if (dump_loss_model(q, skb) != 0)
901661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		goto nla_put_failure;
902661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
903861d7f745f37506bbd90227e97b95baf2a5fac34stephen hemminger	return nla_nest_end(skb, nla);
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9051e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardynla_put_failure:
906861d7f745f37506bbd90227e97b95baf2a5fac34stephen hemminger	nlmsg_trim(skb, nla);
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
91010f6dfcfde884441db89dc66b945d6c948e1d356stephen hemmingerstatic int netem_dump_class(struct Qdisc *sch, unsigned long cl,
91110f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger			  struct sk_buff *skb, struct tcmsg *tcm)
91210f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger{
91310f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	struct netem_sched_data *q = qdisc_priv(sch);
91410f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger
91550612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	if (cl != 1 || !q->qdisc) 	/* only one class */
91610f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger		return -ENOENT;
91710f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger
91810f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	tcm->tcm_handle |= TC_H_MIN(1);
91910f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	tcm->tcm_info = q->qdisc->handle;
92010f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger
92110f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	return 0;
92210f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger}
92310f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger
92410f6dfcfde884441db89dc66b945d6c948e1d356stephen hemmingerstatic int netem_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
92510f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger		     struct Qdisc **old)
92610f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger{
92710f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	struct netem_sched_data *q = qdisc_priv(sch);
92810f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger
92910f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	sch_tree_lock(sch);
93010f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	*old = q->qdisc;
93110f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	q->qdisc = new;
93250612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	if (*old) {
93350612537e9ab29693122fab20fc1eed235054ffeEric Dumazet		qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
93450612537e9ab29693122fab20fc1eed235054ffeEric Dumazet		qdisc_reset(*old);
93550612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	}
93610f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	sch_tree_unlock(sch);
93710f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger
93810f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	return 0;
93910f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger}
94010f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger
94110f6dfcfde884441db89dc66b945d6c948e1d356stephen hemmingerstatic struct Qdisc *netem_leaf(struct Qdisc *sch, unsigned long arg)
94210f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger{
94310f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	struct netem_sched_data *q = qdisc_priv(sch);
94410f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	return q->qdisc;
94510f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger}
94610f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger
94710f6dfcfde884441db89dc66b945d6c948e1d356stephen hemmingerstatic unsigned long netem_get(struct Qdisc *sch, u32 classid)
94810f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger{
94910f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	return 1;
95010f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger}
95110f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger
95210f6dfcfde884441db89dc66b945d6c948e1d356stephen hemmingerstatic void netem_put(struct Qdisc *sch, unsigned long arg)
95310f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger{
95410f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger}
95510f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger
95610f6dfcfde884441db89dc66b945d6c948e1d356stephen hemmingerstatic void netem_walk(struct Qdisc *sch, struct qdisc_walker *walker)
95710f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger{
95810f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	if (!walker->stop) {
95910f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger		if (walker->count >= walker->skip)
96010f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger			if (walker->fn(sch, 1, walker) < 0) {
96110f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger				walker->stop = 1;
96210f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger				return;
96310f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger			}
96410f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger		walker->count++;
96510f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	}
96610f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger}
96710f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger
96810f6dfcfde884441db89dc66b945d6c948e1d356stephen hemmingerstatic const struct Qdisc_class_ops netem_class_ops = {
96910f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	.graft		=	netem_graft,
97010f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	.leaf		=	netem_leaf,
97110f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	.get		=	netem_get,
97210f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	.put		=	netem_put,
97310f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	.walk		=	netem_walk,
97410f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	.dump		=	netem_dump_class,
97510f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger};
97610f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger
97720fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazetstatic struct Qdisc_ops netem_qdisc_ops __read_mostly = {
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.id		=	"netem",
97910f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	.cl_ops		=	&netem_class_ops,
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.priv_size	=	sizeof(struct netem_sched_data),
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.enqueue	=	netem_enqueue,
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.dequeue	=	netem_dequeue,
98377be155cba4e163e8bba9fd27222a8b6189ec4f7Jarek Poplawski	.peek		=	qdisc_peek_dequeued,
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.drop		=	netem_drop,
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.init		=	netem_init,
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.reset		=	netem_reset,
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.destroy	=	netem_destroy,
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.change		=	netem_change,
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.dump		=	netem_dump,
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner		=	THIS_MODULE,
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init netem_module_init(void)
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
996eb229c4cdc3389682cda20adb015ba767950a220Stephen Hemminger	pr_info("netem: version " VERSION "\n");
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return register_qdisc(&netem_qdisc_ops);
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit netem_module_exit(void)
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unregister_qdisc(&netem_qdisc_ops);
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(netem_module_init)
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(netem_module_exit)
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
1006