sch_netem.c revision 960fb66e520a405dde39ff883f17ff2669c13d85
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>
29e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet#include <net/inet_ecn.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31250a65f78265940ac33a2dd2002924e6126efe14stephen hemminger#define VERSION "1.3"
32eb229c4cdc3389682cda20adb015ba767950a220Stephen Hemminger
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*	Network Emulation Queuing algorithm.
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	====================================
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	Sources: [1] Mark Carson, Darrin Santay, "NIST Net - A Linux-based
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 Network Emulation Tool
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 [2] Luigi Rizzo, DummyNet for FreeBSD
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 ----------------------------------------------------------------
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 This started out as a simple way to delay outgoing packets to
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 test TCP but has grown to include most of the functionality
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 of a full blown network emulator like NISTnet. It can delay
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 packets and add random jitter (and correlation). The random
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 distribution can be loaded from a table as well to provide
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 normal, Pareto, or experimental curves. Packet loss,
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 duplication, and reordering can also be emulated.
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 This qdisc does not do classification that can be handled in
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 layering other disciplines.  It does not need to do bandwidth
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 control either since that can be handled by using token
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 bucket or other rate control.
54661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
55661b79725fea030803a89a16cda506bac8eeca78stephen hemminger     Correlated Loss Generator models
56661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
57661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	Added generation of correlated loss according to the
58661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	"Gilbert-Elliot" model, a 4-state markov model.
59661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
60661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	References:
61661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	[1] NetemCLG Home http://netgroup.uniroma2.it/NetemCLG
62661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	[2] S. Salsano, F. Ludovici, A. Ordine, "Definition of a general
63661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	and intuitive loss model for packet networks and its implementation
64661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	in the Netem module in the Linux kernel", available in [1]
65661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
66661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	Authors: Stefano Salsano <stefano.salsano at uniroma2.it
67661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		 Fabio Ludovici <fabio.ludovici at yahoo.it>
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct netem_sched_data {
7150612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	/* internal t(ime)fifo qdisc uses sch->q and sch->limit */
7250612537e9ab29693122fab20fc1eed235054ffeEric Dumazet
7350612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	/* optional qdisc for classful handling (NULL at netem init) */
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct Qdisc	*qdisc;
7550612537e9ab29693122fab20fc1eed235054ffeEric Dumazet
7659cb5c6734021acc68590c7c2e0e92ad9a4952c6Patrick McHardy	struct qdisc_watchdog watchdog;
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
78b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger	psched_tdiff_t latency;
79b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger	psched_tdiff_t jitter;
80b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 loss;
82e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet	u32 ecn;
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 limit;
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 counter;
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 gap;
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u32 duplicate;
870dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	u32 reorder;
88c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger	u32 corrupt;
897bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer	u32 rate;
9090b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	s32 packet_overhead;
9190b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	u32 cell_size;
9290b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	u32 cell_size_reciprocal;
9390b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	s32 cell_overhead;
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct crndstate {
96b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger		u32 last;
97b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger		u32 rho;
98c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger	} delay_cor, loss_cor, dup_cor, reorder_cor, corrupt_cor;
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct disttable {
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		u32  size;
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		s16 table[0];
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} *delay_dist;
104661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
105661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	enum  {
106661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		CLG_RANDOM,
107661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		CLG_4_STATES,
108661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		CLG_GILB_ELL,
109661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	} loss_model;
110661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
111661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	/* Correlated Loss Generation models */
112661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	struct clgstate {
113661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		/* state of the Markov chain */
114661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		u8 state;
115661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
116661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		/* 4-states and Gilbert-Elliot models */
117661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		u32 a1;	/* p13 for 4-states or p for GE */
118661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		u32 a2;	/* p31 for 4-states or r for GE */
119661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		u32 a3;	/* p32 for 4-states or h for GE */
120661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		u32 a4;	/* p14 for 4-states or 1-k for GE */
121661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		u32 a5; /* p23 used only in 4-states */
122661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	} clg;
123661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12650612537e9ab29693122fab20fc1eed235054ffeEric Dumazet/* Time stamp put into socket buffer control block
12750612537e9ab29693122fab20fc1eed235054ffeEric Dumazet * Only valid when skbs are in our internal t(ime)fifo queue.
12850612537e9ab29693122fab20fc1eed235054ffeEric Dumazet */
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct netem_skb_cb {
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	psched_time_t	time_to_send;
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1335f86173bdf15981ca49d0434f638b68f70a35644Jussi Kivilinnastatic inline struct netem_skb_cb *netem_skb_cb(struct sk_buff *skb)
1345f86173bdf15981ca49d0434f638b68f70a35644Jussi Kivilinna{
13516bda13d90c8d5da243e2cfa1677e62ecce26860David S. Miller	qdisc_cb_private_validate(skb, sizeof(struct netem_skb_cb));
136175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna	return (struct netem_skb_cb *)qdisc_skb_cb(skb)->data;
1375f86173bdf15981ca49d0434f638b68f70a35644Jussi Kivilinna}
1385f86173bdf15981ca49d0434f638b68f70a35644Jussi Kivilinna
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* init_crandom - initialize correlated random number generator
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Use entropy source for initial seed.
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void init_crandom(struct crndstate *state, unsigned long rho)
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	state->rho = rho;
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	state->last = net_random();
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* get_crandom - correlated random number generator
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Next number depends on last value.
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * rho is scaled to avoid floating point.
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
152b407621c35ed5f9a0734e57472e9539117963768Stephen Hemmingerstatic u32 get_crandom(struct crndstate *state)
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u64 value, rho;
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long answer;
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
157bb2f8cc0ecf025d6d3947e0389434650023f432eStephen Hemminger	if (state->rho == 0)	/* no correlation */
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return net_random();
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	value = net_random();
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rho = (u64)state->rho + 1;
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	answer = (value * ((1ull<<32) - rho) + state->last * rho) >> 32;
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	state->last = answer;
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return answer;
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
167661b79725fea030803a89a16cda506bac8eeca78stephen hemminger/* loss_4state - 4-state model loss generator
168661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * Generates losses according to the 4-state Markov chain adopted in
169661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * the GI (General and Intuitive) loss model.
170661b79725fea030803a89a16cda506bac8eeca78stephen hemminger */
171661b79725fea030803a89a16cda506bac8eeca78stephen hemmingerstatic bool loss_4state(struct netem_sched_data *q)
172661b79725fea030803a89a16cda506bac8eeca78stephen hemminger{
173661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	struct clgstate *clg = &q->clg;
174661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	u32 rnd = net_random();
175661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
176661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	/*
17725985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	 * Makes a comparison between rnd and the transition
178661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	 * probabilities outgoing from the current state, then decides the
179661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	 * next state and if the next packet has to be transmitted or lost.
180661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	 * The four states correspond to:
181661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	 *   1 => successfully transmitted packets within a gap period
182661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	 *   4 => isolated losses within a gap period
183661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	 *   3 => lost packets within a burst period
184661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	 *   2 => successfully transmitted packets within a burst period
185661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	 */
186661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	switch (clg->state) {
187661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	case 1:
188661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		if (rnd < clg->a4) {
189661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			clg->state = 4;
190661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			return true;
191661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		} else if (clg->a4 < rnd && rnd < clg->a1) {
192661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			clg->state = 3;
193661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			return true;
194661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		} else if (clg->a1 < rnd)
195661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			clg->state = 1;
196661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
197661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		break;
198661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	case 2:
199661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		if (rnd < clg->a5) {
200661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			clg->state = 3;
201661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			return true;
202661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		} else
203661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			clg->state = 2;
204661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
205661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		break;
206661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	case 3:
207661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		if (rnd < clg->a3)
208661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			clg->state = 2;
209661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		else if (clg->a3 < rnd && rnd < clg->a2 + clg->a3) {
210661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			clg->state = 1;
211661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			return true;
212661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		} else if (clg->a2 + clg->a3 < rnd) {
213661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			clg->state = 3;
214661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			return true;
215661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		}
216661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		break;
217661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	case 4:
218661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		clg->state = 1;
219661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		break;
220661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	}
221661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
222661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	return false;
223661b79725fea030803a89a16cda506bac8eeca78stephen hemminger}
224661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
225661b79725fea030803a89a16cda506bac8eeca78stephen hemminger/* loss_gilb_ell - Gilbert-Elliot model loss generator
226661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * Generates losses according to the Gilbert-Elliot loss model or
227661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * its special cases  (Gilbert or Simple Gilbert)
228661b79725fea030803a89a16cda506bac8eeca78stephen hemminger *
22925985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * Makes a comparison between random number and the transition
230661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * probabilities outgoing from the current state, then decides the
23125985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * next state. A second random number is extracted and the comparison
232661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * with the loss probability of the current state decides if the next
233661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * packet will be transmitted or lost.
234661b79725fea030803a89a16cda506bac8eeca78stephen hemminger */
235661b79725fea030803a89a16cda506bac8eeca78stephen hemmingerstatic bool loss_gilb_ell(struct netem_sched_data *q)
236661b79725fea030803a89a16cda506bac8eeca78stephen hemminger{
237661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	struct clgstate *clg = &q->clg;
238661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
239661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	switch (clg->state) {
240661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	case 1:
241661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		if (net_random() < clg->a1)
242661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			clg->state = 2;
243661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		if (net_random() < clg->a4)
244661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			return true;
245661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	case 2:
246661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		if (net_random() < clg->a2)
247661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			clg->state = 1;
248661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		if (clg->a3 > net_random())
249661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			return true;
250661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	}
251661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
252661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	return false;
253661b79725fea030803a89a16cda506bac8eeca78stephen hemminger}
254661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
255661b79725fea030803a89a16cda506bac8eeca78stephen hemmingerstatic bool loss_event(struct netem_sched_data *q)
256661b79725fea030803a89a16cda506bac8eeca78stephen hemminger{
257661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	switch (q->loss_model) {
258661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	case CLG_RANDOM:
259661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		/* Random packet drop 0 => none, ~0 => all */
260661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		return q->loss && q->loss >= get_crandom(&q->loss_cor);
261661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
262661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	case CLG_4_STATES:
263661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		/* 4state loss model algorithm (used also for GI model)
264661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		* Extracts a value from the markov 4 state loss generator,
265661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		* if it is 1 drops a packet and if needed writes the event in
266661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		* the kernel logs
267661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		*/
268661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		return loss_4state(q);
269661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
270661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	case CLG_GILB_ELL:
271661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		/* Gilbert-Elliot loss model algorithm
272661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		* Extracts a value from the Gilbert-Elliot loss generator,
273661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		* if it is 1 drops a packet and if needed writes the event in
274661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		* the kernel logs
275661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		*/
276661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		return loss_gilb_ell(q);
277661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	}
278661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
279661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	return false;	/* not reached */
280661b79725fea030803a89a16cda506bac8eeca78stephen hemminger}
281661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
282661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* tabledist - return a pseudo-randomly distributed value with mean mu and
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * std deviation sigma.  Uses table lookup to approximate the desired
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * distribution, and a uniformly-distributed pseudo-random source.
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
287b407621c35ed5f9a0734e57472e9539117963768Stephen Hemmingerstatic psched_tdiff_t tabledist(psched_tdiff_t mu, psched_tdiff_t sigma,
288b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger				struct crndstate *state,
289b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger				const struct disttable *dist)
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
291b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger	psched_tdiff_t x;
292b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger	long t;
293b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger	u32 rnd;
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sigma == 0)
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return mu;
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rnd = get_crandom(state);
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* default uniform distribution */
30110297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki	if (dist == NULL)
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return (rnd % (2*sigma)) - sigma + mu;
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	t = dist->table[rnd % dist->size];
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	x = (sigma % NETEM_DIST_SCALE) * t;
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (x >= 0)
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		x += NETEM_DIST_SCALE/2;
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		x -= NETEM_DIST_SCALE/2;
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return  x / NETEM_DIST_SCALE + (sigma / NETEM_DIST_SCALE) * t + mu;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
31490b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeiferstatic psched_time_t packet_len_2_sched_time(unsigned int len, struct netem_sched_data *q)
3157bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer{
31690b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	u64 ticks;
317fc33cc72423ed3474cd51bc8bd7c1cdc22a78e1aEric Dumazet
31890b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	len += q->packet_overhead;
31990b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer
32090b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	if (q->cell_size) {
32190b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer		u32 cells = reciprocal_divide(len, q->cell_size_reciprocal);
32290b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer
32390b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer		if (len > cells * q->cell_size)	/* extra cell needed for remainder */
32490b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer			cells++;
32590b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer		len = cells * (q->cell_size + q->cell_overhead);
32690b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	}
32790b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer
32890b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	ticks = (u64)len * NSEC_PER_SEC;
32990b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer
33090b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	do_div(ticks, q->rate);
331fc33cc72423ed3474cd51bc8bd7c1cdc22a78e1aEric Dumazet	return PSCHED_NS2TICKS(ticks);
3327bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer}
3337bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer
334960fb66e520a405dde39ff883f17ff2669c13d85Eric Dumazetstatic void tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch)
33550612537e9ab29693122fab20fc1eed235054ffeEric Dumazet{
33650612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	struct sk_buff_head *list = &sch->q;
33750612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	psched_time_t tnext = netem_skb_cb(nskb)->time_to_send;
338960fb66e520a405dde39ff883f17ff2669c13d85Eric Dumazet	struct sk_buff *skb = skb_peek_tail(list);
33950612537e9ab29693122fab20fc1eed235054ffeEric Dumazet
340960fb66e520a405dde39ff883f17ff2669c13d85Eric Dumazet	/* Optimize for add at tail */
341960fb66e520a405dde39ff883f17ff2669c13d85Eric Dumazet	if (likely(!skb || tnext >= netem_skb_cb(skb)->time_to_send))
342960fb66e520a405dde39ff883f17ff2669c13d85Eric Dumazet		return __skb_queue_tail(list, nskb);
34350612537e9ab29693122fab20fc1eed235054ffeEric Dumazet
344960fb66e520a405dde39ff883f17ff2669c13d85Eric Dumazet	skb_queue_reverse_walk(list, skb) {
345960fb66e520a405dde39ff883f17ff2669c13d85Eric Dumazet		if (tnext >= netem_skb_cb(skb)->time_to_send)
346960fb66e520a405dde39ff883f17ff2669c13d85Eric Dumazet			break;
34750612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	}
34850612537e9ab29693122fab20fc1eed235054ffeEric Dumazet
349960fb66e520a405dde39ff883f17ff2669c13d85Eric Dumazet	__skb_queue_after(list, skb, nskb);
35050612537e9ab29693122fab20fc1eed235054ffeEric Dumazet}
35150612537e9ab29693122fab20fc1eed235054ffeEric Dumazet
3520afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger/*
3530afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger * Insert one skb into qdisc.
3540afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger * Note: parent depends on return value to account for queue length.
3550afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger * 	NET_XMIT_DROP: queue length didn't change.
3560afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger *      NET_XMIT_SUCCESS: one skb was queued.
3570afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger */
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netem_sched_data *q = qdisc_priv(sch);
36189e1df74f841fc31e81838d30594c4eff01859f8Guillaume Chazarain	/* We don't fill cb now as skb_unshare() may invalidate it */
36289e1df74f841fc31e81838d30594c4eff01859f8Guillaume Chazarain	struct netem_skb_cb *cb;
3630afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	struct sk_buff *skb2;
3640afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	int count = 1;
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3660afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	/* Random duplication */
3670afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	if (q->duplicate && q->duplicate >= get_crandom(&q->dup_cor))
3680afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger		++count;
3690afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger
370661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	/* Drop packet? */
371e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet	if (loss_event(q)) {
372e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet		if (q->ecn && INET_ECN_set_ce(skb))
373e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet			sch->qstats.drops++; /* mark packet */
374e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet		else
375e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet			--count;
376e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet	}
3770afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	if (count == 0) {
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sch->qstats.drops++;
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree_skb(skb);
380c27f339af90bb874a7a9c680b17abfd32d4a727bJarek Poplawski		return NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3834e8a5201506423e0241202de1349422af4260296David S. Miller	skb_orphan(skb);
3844e8a5201506423e0241202de1349422af4260296David S. Miller
3850afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	/*
3860afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	 * If we need to duplicate packet, then re-insert at top of the
3870afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	 * qdisc tree, since parent queuer expects that only one
3880afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	 * skb will be queued.
3890afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	 */
3900afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger	if (count > 1 && (skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) {
3917698b4fcabcd790efc4f226bada1e7b5870653afDavid S. Miller		struct Qdisc *rootq = qdisc_root(sch);
3920afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger		u32 dupsave = q->duplicate; /* prevent duplicating a dup... */
3930afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger		q->duplicate = 0;
3940afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger
3955f86173bdf15981ca49d0434f638b68f70a35644Jussi Kivilinna		qdisc_enqueue_root(skb2, rootq);
3960afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger		q->duplicate = dupsave;
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
399c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger	/*
400c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger	 * Randomized packet corruption.
401c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger	 * Make copy if needed since we are modifying
402c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger	 * If packet is going to be hardware checksummed, then
403c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger	 * do it now in software before we mangle it.
404c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger	 */
405c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger	if (q->corrupt && q->corrupt >= get_crandom(&q->corrupt_cor)) {
406f64f9e719261a87818dd192a3a2352e5b20fbd0fJoe Perches		if (!(skb = skb_unshare(skb, GFP_ATOMIC)) ||
407f64f9e719261a87818dd192a3a2352e5b20fbd0fJoe Perches		    (skb->ip_summed == CHECKSUM_PARTIAL &&
408116a0fc31c6c9b8fc821be5a96e5bf0b43260131Eric Dumazet		     skb_checksum_help(skb)))
409116a0fc31c6c9b8fc821be5a96e5bf0b43260131Eric Dumazet			return qdisc_drop(skb, sch);
410c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger
411c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger		skb->data[net_random() % skb_headlen(skb)] ^= 1<<(net_random() % 8);
412c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger	}
413c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger
414960fb66e520a405dde39ff883f17ff2669c13d85Eric Dumazet	if (unlikely(skb_queue_len(&sch->q) >= sch->limit))
415960fb66e520a405dde39ff883f17ff2669c13d85Eric Dumazet		return qdisc_reshape_fail(skb, sch);
416960fb66e520a405dde39ff883f17ff2669c13d85Eric Dumazet
417960fb66e520a405dde39ff883f17ff2669c13d85Eric Dumazet	sch->qstats.backlog += qdisc_pkt_len(skb);
418960fb66e520a405dde39ff883f17ff2669c13d85Eric Dumazet
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;
450960fb66e520a405dde39ff883f17ff2669c13d85Eric Dumazet		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.requeues++;
461378a2f090f7a478704a372a4869b8a9ac206234eJarek Poplawski	}
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46310f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	return NET_XMIT_SUCCESS;
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
466cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazetstatic unsigned int netem_drop(struct Qdisc *sch)
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netem_sched_data *q = qdisc_priv(sch);
46950612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	unsigned int len;
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47150612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	len = qdisc_queue_drop(sch);
47250612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	if (!len && q->qdisc && q->qdisc->ops->drop)
47350612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	    len = q->qdisc->ops->drop(q->qdisc);
47450612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	if (len)
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sch->qstats.drops++;
47650612537e9ab29693122fab20fc1eed235054ffeEric Dumazet
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return len;
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sk_buff *netem_dequeue(struct Qdisc *sch)
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netem_sched_data *q = qdisc_priv(sch);
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
485fd245a4adb5288eac37250875f237c40a20a1944Eric Dumazet	if (qdisc_is_throttled(sch))
48611274e5a43266d531140530adebead6903380cafStephen Hemminger		return NULL;
48711274e5a43266d531140530adebead6903380cafStephen Hemminger
48850612537e9ab29693122fab20fc1eed235054ffeEric Dumazettfifo_dequeue:
48950612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	skb = qdisc_peek_head(sch);
490771018e76aaa6474be20a53c20458bcae8b00485Stephen Hemminger	if (skb) {
4915f86173bdf15981ca49d0434f638b68f70a35644Jussi Kivilinna		const struct netem_skb_cb *cb = netem_skb_cb(skb);
4920f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger
4930f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger		/* if more time remaining? */
49450612537e9ab29693122fab20fc1eed235054ffeEric Dumazet		if (cb->time_to_send <= psched_get_time()) {
495cd961c2ca98efbe7d738ca8720673fc03538b2b1Eric Dumazet			__skb_unlink(skb, &sch->q);
496cd961c2ca98efbe7d738ca8720673fc03538b2b1Eric Dumazet			sch->qstats.backlog -= qdisc_pkt_len(skb);
49703c05f0d4bb0c267edf12d614025a40e33c5a6f9Jarek Poplawski
4988caf153974f2274301e583fda732cc8e5b80331fJarek Poplawski#ifdef CONFIG_NET_CLS_ACT
4998caf153974f2274301e583fda732cc8e5b80331fJarek Poplawski			/*
5008caf153974f2274301e583fda732cc8e5b80331fJarek Poplawski			 * If it's at ingress let's pretend the delay is
5018caf153974f2274301e583fda732cc8e5b80331fJarek Poplawski			 * from the network (tstamp will be updated).
5028caf153974f2274301e583fda732cc8e5b80331fJarek Poplawski			 */
5038caf153974f2274301e583fda732cc8e5b80331fJarek Poplawski			if (G_TC_FROM(skb->tc_verd) & AT_INGRESS)
5048caf153974f2274301e583fda732cc8e5b80331fJarek Poplawski				skb->tstamp.tv64 = 0;
5058caf153974f2274301e583fda732cc8e5b80331fJarek Poplawski#endif
50610f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger
50750612537e9ab29693122fab20fc1eed235054ffeEric Dumazet			if (q->qdisc) {
50850612537e9ab29693122fab20fc1eed235054ffeEric Dumazet				int err = qdisc_enqueue(skb, q->qdisc);
50950612537e9ab29693122fab20fc1eed235054ffeEric Dumazet
51050612537e9ab29693122fab20fc1eed235054ffeEric Dumazet				if (unlikely(err != NET_XMIT_SUCCESS)) {
51150612537e9ab29693122fab20fc1eed235054ffeEric Dumazet					if (net_xmit_drop_count(err)) {
51250612537e9ab29693122fab20fc1eed235054ffeEric Dumazet						sch->qstats.drops++;
51350612537e9ab29693122fab20fc1eed235054ffeEric Dumazet						qdisc_tree_decrease_qlen(sch, 1);
51450612537e9ab29693122fab20fc1eed235054ffeEric Dumazet					}
51550612537e9ab29693122fab20fc1eed235054ffeEric Dumazet				}
51650612537e9ab29693122fab20fc1eed235054ffeEric Dumazet				goto tfifo_dequeue;
51750612537e9ab29693122fab20fc1eed235054ffeEric Dumazet			}
51850612537e9ab29693122fab20fc1eed235054ffeEric Dumazetdeliver:
51910f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger			qdisc_unthrottled(sch);
52010f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger			qdisc_bstats_update(sch, skb);
5210f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger			return skb;
52207aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger		}
52311274e5a43266d531140530adebead6903380cafStephen Hemminger
52450612537e9ab29693122fab20fc1eed235054ffeEric Dumazet		if (q->qdisc) {
52550612537e9ab29693122fab20fc1eed235054ffeEric Dumazet			skb = q->qdisc->ops->dequeue(q->qdisc);
52650612537e9ab29693122fab20fc1eed235054ffeEric Dumazet			if (skb)
52750612537e9ab29693122fab20fc1eed235054ffeEric Dumazet				goto deliver;
52850612537e9ab29693122fab20fc1eed235054ffeEric Dumazet		}
52911274e5a43266d531140530adebead6903380cafStephen Hemminger		qdisc_watchdog_schedule(&q->watchdog, cb->time_to_send);
5300f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger	}
5310f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger
53250612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	if (q->qdisc) {
53350612537e9ab29693122fab20fc1eed235054ffeEric Dumazet		skb = q->qdisc->ops->dequeue(q->qdisc);
53450612537e9ab29693122fab20fc1eed235054ffeEric Dumazet		if (skb)
53550612537e9ab29693122fab20fc1eed235054ffeEric Dumazet			goto deliver;
53650612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	}
5370f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger	return NULL;
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void netem_reset(struct Qdisc *sch)
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netem_sched_data *q = qdisc_priv(sch);
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
54450612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	qdisc_reset_queue(sch);
54550612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	if (q->qdisc)
54650612537e9ab29693122fab20fc1eed235054ffeEric Dumazet		qdisc_reset(q->qdisc);
54759cb5c6734021acc68590c7c2e0e92ad9a4952c6Patrick McHardy	qdisc_watchdog_cancel(&q->watchdog);
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5506373a9a286bdd955a76924cee88a2f8f784988b1stephen hemmingerstatic void dist_free(struct disttable *d)
5516373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger{
5526373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger	if (d) {
5536373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger		if (is_vmalloc_addr(d))
5546373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger			vfree(d);
5556373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger		else
5566373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger			kfree(d);
5576373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger	}
5586373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger}
5596373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Distribution data is a variable size payload containing
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * signed 16 bit values.
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
5641e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardystatic int get_dist_table(struct Qdisc *sch, const struct nlattr *attr)
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netem_sched_data *q = qdisc_priv(sch);
5676373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger	size_t n = nla_len(attr)/sizeof(__s16);
5681e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	const __s16 *data = nla_data(attr);
5697698b4fcabcd790efc4f226bada1e7b5870653afDavid S. Miller	spinlock_t *root_lock;
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct disttable *d;
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
5726373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger	size_t s;
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
574df173bda2639ac744ccf596ec1f8f7e66fe4c343stephen hemminger	if (n > NETEM_DIST_MAX)
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5776373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger	s = sizeof(struct disttable) + n * sizeof(s16);
578bb52c7acf871537a468433775151339f783d2e8cEric Dumazet	d = kmalloc(s, GFP_KERNEL | __GFP_NOWARN);
5796373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger	if (!d)
5806373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger		d = vmalloc(s);
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!d)
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	d->size = n;
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < n; i++)
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		d->table[i] = data[i];
58710297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki
588102396ae65108b026e4e1868e30fa013f45a169eJarek Poplawski	root_lock = qdisc_root_sleeping_lock(sch);
5897698b4fcabcd790efc4f226bada1e7b5870653afDavid S. Miller
5907698b4fcabcd790efc4f226bada1e7b5870653afDavid S. Miller	spin_lock_bh(root_lock);
591bb52c7acf871537a468433775151339f783d2e8cEric Dumazet	swap(q->delay_dist, d);
5927698b4fcabcd790efc4f226bada1e7b5870653afDavid S. Miller	spin_unlock_bh(root_lock);
593bb52c7acf871537a468433775151339f783d2e8cEric Dumazet
594bb52c7acf871537a468433775151339f783d2e8cEric Dumazet	dist_free(d);
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
598265eb67fb4e16be8e46a51e1e4e2ecd99fb15219Stephen Hemmingerstatic void get_correlation(struct Qdisc *sch, const struct nlattr *attr)
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netem_sched_data *q = qdisc_priv(sch);
6011e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	const struct tc_netem_corr *c = nla_data(attr);
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_crandom(&q->delay_cor, c->delay_corr);
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_crandom(&q->loss_cor, c->loss_corr);
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	init_crandom(&q->dup_cor, c->dup_corr);
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
608265eb67fb4e16be8e46a51e1e4e2ecd99fb15219Stephen Hemmingerstatic void get_reorder(struct Qdisc *sch, const struct nlattr *attr)
6090dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger{
6100dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	struct netem_sched_data *q = qdisc_priv(sch);
6111e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	const struct tc_netem_reorder *r = nla_data(attr);
6120dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger
6130dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	q->reorder = r->probability;
6140dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	init_crandom(&q->reorder_cor, r->correlation);
6150dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger}
6160dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger
617265eb67fb4e16be8e46a51e1e4e2ecd99fb15219Stephen Hemmingerstatic void get_corrupt(struct Qdisc *sch, const struct nlattr *attr)
618c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger{
619c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger	struct netem_sched_data *q = qdisc_priv(sch);
6201e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy	const struct tc_netem_corrupt *r = nla_data(attr);
621c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger
622c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger	q->corrupt = r->probability;
623c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger	init_crandom(&q->corrupt_cor, r->correlation);
624c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger}
625c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger
6267bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeiferstatic void get_rate(struct Qdisc *sch, const struct nlattr *attr)
6277bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer{
6287bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer	struct netem_sched_data *q = qdisc_priv(sch);
6297bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer	const struct tc_netem_rate *r = nla_data(attr);
6307bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer
6317bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer	q->rate = r->rate;
63290b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	q->packet_overhead = r->packet_overhead;
63390b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	q->cell_size = r->cell_size;
63490b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	if (q->cell_size)
63590b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer		q->cell_size_reciprocal = reciprocal_value(q->cell_size);
63690b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	q->cell_overhead = r->cell_overhead;
6377bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer}
6387bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer
639661b79725fea030803a89a16cda506bac8eeca78stephen hemmingerstatic int get_loss_clg(struct Qdisc *sch, const struct nlattr *attr)
640661b79725fea030803a89a16cda506bac8eeca78stephen hemminger{
641661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	struct netem_sched_data *q = qdisc_priv(sch);
642661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	const struct nlattr *la;
643661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	int rem;
644661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
645661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	nla_for_each_nested(la, attr, rem) {
646661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		u16 type = nla_type(la);
647661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
648661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		switch(type) {
649661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		case NETEM_LOSS_GI: {
650661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			const struct tc_netem_gimodel *gi = nla_data(la);
651661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
6522494654d4890316e7340fb8b3458daad0474a1b9stephen hemminger			if (nla_len(la) < sizeof(struct tc_netem_gimodel)) {
653661b79725fea030803a89a16cda506bac8eeca78stephen hemminger				pr_info("netem: incorrect gi model size\n");
654661b79725fea030803a89a16cda506bac8eeca78stephen hemminger				return -EINVAL;
655661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			}
656661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
657661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			q->loss_model = CLG_4_STATES;
658661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
659661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			q->clg.state = 1;
660661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			q->clg.a1 = gi->p13;
661661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			q->clg.a2 = gi->p31;
662661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			q->clg.a3 = gi->p32;
663661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			q->clg.a4 = gi->p14;
664661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			q->clg.a5 = gi->p23;
665661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			break;
666661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		}
667661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
668661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		case NETEM_LOSS_GE: {
669661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			const struct tc_netem_gemodel *ge = nla_data(la);
670661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
6712494654d4890316e7340fb8b3458daad0474a1b9stephen hemminger			if (nla_len(la) < sizeof(struct tc_netem_gemodel)) {
6722494654d4890316e7340fb8b3458daad0474a1b9stephen hemminger				pr_info("netem: incorrect ge model size\n");
673661b79725fea030803a89a16cda506bac8eeca78stephen hemminger				return -EINVAL;
674661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			}
675661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
676661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			q->loss_model = CLG_GILB_ELL;
677661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			q->clg.state = 1;
678661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			q->clg.a1 = ge->p;
679661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			q->clg.a2 = ge->r;
680661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			q->clg.a3 = ge->h;
681661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			q->clg.a4 = ge->k1;
682661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			break;
683661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		}
684661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
685661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		default:
686661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			pr_info("netem: unknown loss type %u\n", type);
687661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			return -EINVAL;
688661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		}
689661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	}
690661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
691661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	return 0;
692661b79725fea030803a89a16cda506bac8eeca78stephen hemminger}
693661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
69427a3421e4821734bc19496faa77b380605dc3b23Patrick McHardystatic const struct nla_policy netem_policy[TCA_NETEM_MAX + 1] = {
69527a3421e4821734bc19496faa77b380605dc3b23Patrick McHardy	[TCA_NETEM_CORR]	= { .len = sizeof(struct tc_netem_corr) },
69627a3421e4821734bc19496faa77b380605dc3b23Patrick McHardy	[TCA_NETEM_REORDER]	= { .len = sizeof(struct tc_netem_reorder) },
69727a3421e4821734bc19496faa77b380605dc3b23Patrick McHardy	[TCA_NETEM_CORRUPT]	= { .len = sizeof(struct tc_netem_corrupt) },
6987bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer	[TCA_NETEM_RATE]	= { .len = sizeof(struct tc_netem_rate) },
699661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	[TCA_NETEM_LOSS]	= { .type = NLA_NESTED },
700e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet	[TCA_NETEM_ECN]		= { .type = NLA_U32 },
70127a3421e4821734bc19496faa77b380605dc3b23Patrick McHardy};
70227a3421e4821734bc19496faa77b380605dc3b23Patrick McHardy
7032c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Grafstatic int parse_attr(struct nlattr *tb[], int maxtype, struct nlattr *nla,
7042c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf		      const struct nla_policy *policy, int len)
7052c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf{
7062c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf	int nested_len = nla_len(nla) - NLA_ALIGN(len);
7072c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf
708661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	if (nested_len < 0) {
709661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		pr_info("netem: invalid attributes len %d\n", nested_len);
7102c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf		return -EINVAL;
711661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	}
712661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
7132c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf	if (nested_len >= nla_attr_size(0))
7142c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf		return nla_parse(tb, maxtype, nla_data(nla) + NLA_ALIGN(len),
7152c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf				 nested_len, policy);
716661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
7172c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf	memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
7182c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf	return 0;
7192c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf}
7202c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf
721c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger/* Parse netlink message to set options */
7221e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardystatic int netem_change(struct Qdisc *sch, struct nlattr *opt)
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netem_sched_data *q = qdisc_priv(sch);
725b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy	struct nlattr *tb[TCA_NETEM_MAX + 1];
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tc_netem_qopt *qopt;
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
72810297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki
729b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy	if (opt == NULL)
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7322c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf	qopt = nla_data(opt);
7332c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf	ret = parse_attr(tb, TCA_NETEM_MAX, opt, netem_policy, sizeof(*qopt));
734b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy	if (ret < 0)
735b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy		return ret;
736b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy
73750612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	sch->limit = qopt->limit;
73810297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q->latency = qopt->latency;
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q->jitter = qopt->jitter;
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q->limit = qopt->limit;
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q->gap = qopt->gap;
7430dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	q->counter = 0;
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q->loss = qopt->loss;
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	q->duplicate = qopt->duplicate;
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
747bb2f8cc0ecf025d6d3947e0389434650023f432eStephen Hemminger	/* for compatibility with earlier versions.
748bb2f8cc0ecf025d6d3947e0389434650023f432eStephen Hemminger	 * if gap is set, need to assume 100% probability
7490dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	 */
750a362e0a7890c735a3ef63aab12d71ecfc6e6f4a5Stephen Hemminger	if (q->gap)
751a362e0a7890c735a3ef63aab12d71ecfc6e6f4a5Stephen Hemminger		q->reorder = ~0;
7520dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger
753265eb67fb4e16be8e46a51e1e4e2ecd99fb15219Stephen Hemminger	if (tb[TCA_NETEM_CORR])
754265eb67fb4e16be8e46a51e1e4e2ecd99fb15219Stephen Hemminger		get_correlation(sch, tb[TCA_NETEM_CORR]);
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
756b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy	if (tb[TCA_NETEM_DELAY_DIST]) {
757b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy		ret = get_dist_table(sch, tb[TCA_NETEM_DELAY_DIST]);
758b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy		if (ret)
759b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy			return ret;
760b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy	}
761c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger
762265eb67fb4e16be8e46a51e1e4e2ecd99fb15219Stephen Hemminger	if (tb[TCA_NETEM_REORDER])
763265eb67fb4e16be8e46a51e1e4e2ecd99fb15219Stephen Hemminger		get_reorder(sch, tb[TCA_NETEM_REORDER]);
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
765265eb67fb4e16be8e46a51e1e4e2ecd99fb15219Stephen Hemminger	if (tb[TCA_NETEM_CORRUPT])
766265eb67fb4e16be8e46a51e1e4e2ecd99fb15219Stephen Hemminger		get_corrupt(sch, tb[TCA_NETEM_CORRUPT]);
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7687bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer	if (tb[TCA_NETEM_RATE])
7697bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer		get_rate(sch, tb[TCA_NETEM_RATE]);
7707bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer
771e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet	if (tb[TCA_NETEM_ECN])
772e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet		q->ecn = nla_get_u32(tb[TCA_NETEM_ECN]);
773e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet
774661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	q->loss_model = CLG_RANDOM;
775661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	if (tb[TCA_NETEM_LOSS])
776661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		ret = get_loss_clg(sch, tb[TCA_NETEM_LOSS]);
777661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
778661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	return ret;
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7811e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardystatic int netem_init(struct Qdisc *sch, struct nlattr *opt)
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netem_sched_data *q = qdisc_priv(sch);
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!opt)
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
78959cb5c6734021acc68590c7c2e0e92ad9a4952c6Patrick McHardy	qdisc_watchdog_init(&q->watchdog, sch);
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
791661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	q->loss_model = CLG_RANDOM;
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = netem_change(sch, opt);
79350612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	if (ret)
794250a65f78265940ac33a2dd2002924e6126efe14stephen hemminger		pr_info("netem: change failed\n");
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void netem_destroy(struct Qdisc *sch)
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct netem_sched_data *q = qdisc_priv(sch);
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
80259cb5c6734021acc68590c7c2e0e92ad9a4952c6Patrick McHardy	qdisc_watchdog_cancel(&q->watchdog);
80350612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	if (q->qdisc)
80450612537e9ab29693122fab20fc1eed235054ffeEric Dumazet		qdisc_destroy(q->qdisc);
8056373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger	dist_free(q->delay_dist);
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
808661b79725fea030803a89a16cda506bac8eeca78stephen hemmingerstatic int dump_loss_model(const struct netem_sched_data *q,
809661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			   struct sk_buff *skb)
810661b79725fea030803a89a16cda506bac8eeca78stephen hemminger{
811661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	struct nlattr *nest;
812661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
813661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	nest = nla_nest_start(skb, TCA_NETEM_LOSS);
814661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	if (nest == NULL)
815661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		goto nla_put_failure;
816661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
817661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	switch (q->loss_model) {
818661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	case CLG_RANDOM:
819661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		/* legacy loss model */
820661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		nla_nest_cancel(skb, nest);
821661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		return 0;	/* no data */
822661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
823661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	case CLG_4_STATES: {
824661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		struct tc_netem_gimodel gi = {
825661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			.p13 = q->clg.a1,
826661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			.p31 = q->clg.a2,
827661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			.p32 = q->clg.a3,
828661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			.p14 = q->clg.a4,
829661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			.p23 = q->clg.a5,
830661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		};
831661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
8321b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller		if (nla_put(skb, NETEM_LOSS_GI, sizeof(gi), &gi))
8331b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller			goto nla_put_failure;
834661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		break;
835661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	}
836661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	case CLG_GILB_ELL: {
837661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		struct tc_netem_gemodel ge = {
838661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			.p = q->clg.a1,
839661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			.r = q->clg.a2,
840661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			.h = q->clg.a3,
841661b79725fea030803a89a16cda506bac8eeca78stephen hemminger			.k1 = q->clg.a4,
842661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		};
843661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
8441b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller		if (nla_put(skb, NETEM_LOSS_GE, sizeof(ge), &ge))
8451b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller			goto nla_put_failure;
846661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		break;
847661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	}
848661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	}
849661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
850661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	nla_nest_end(skb, nest);
851661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	return 0;
852661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
853661b79725fea030803a89a16cda506bac8eeca78stephen hemmingernla_put_failure:
854661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	nla_nest_cancel(skb, nest);
855661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	return -1;
856661b79725fea030803a89a16cda506bac8eeca78stephen hemminger}
857661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int netem_dump(struct Qdisc *sch, struct sk_buff *skb)
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const struct netem_sched_data *q = qdisc_priv(sch);
861861d7f745f37506bbd90227e97b95baf2a5fac34stephen hemminger	struct nlattr *nla = (struct nlattr *) skb_tail_pointer(skb);
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tc_netem_qopt qopt;
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct tc_netem_corr cor;
8640dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	struct tc_netem_reorder reorder;
865c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger	struct tc_netem_corrupt corrupt;
8667bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer	struct tc_netem_rate rate;
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qopt.latency = q->latency;
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qopt.jitter = q->jitter;
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qopt.limit = q->limit;
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qopt.loss = q->loss;
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qopt.gap = q->gap;
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qopt.duplicate = q->duplicate;
8741b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller	if (nla_put(skb, TCA_OPTIONS, sizeof(qopt), &qopt))
8751b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller		goto nla_put_failure;
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cor.delay_corr = q->delay_cor.rho;
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cor.loss_corr = q->loss_cor.rho;
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cor.dup_corr = q->dup_cor.rho;
8801b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller	if (nla_put(skb, TCA_NETEM_CORR, sizeof(cor), &cor))
8811b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller		goto nla_put_failure;
8820dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger
8830dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	reorder.probability = q->reorder;
8840dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger	reorder.correlation = q->reorder_cor.rho;
8851b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller	if (nla_put(skb, TCA_NETEM_REORDER, sizeof(reorder), &reorder))
8861b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller		goto nla_put_failure;
8870dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger
888c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger	corrupt.probability = q->corrupt;
889c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger	corrupt.correlation = q->corrupt_cor.rho;
8901b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller	if (nla_put(skb, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt))
8911b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller		goto nla_put_failure;
892c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger
8937bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer	rate.rate = q->rate;
89490b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	rate.packet_overhead = q->packet_overhead;
89590b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	rate.cell_size = q->cell_size;
89690b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer	rate.cell_overhead = q->cell_overhead;
8971b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller	if (nla_put(skb, TCA_NETEM_RATE, sizeof(rate), &rate))
8981b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller		goto nla_put_failure;
8997bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer
900e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet	if (q->ecn && nla_put_u32(skb, TCA_NETEM_ECN, q->ecn))
901e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet		goto nla_put_failure;
902e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet
903661b79725fea030803a89a16cda506bac8eeca78stephen hemminger	if (dump_loss_model(q, skb) != 0)
904661b79725fea030803a89a16cda506bac8eeca78stephen hemminger		goto nla_put_failure;
905661b79725fea030803a89a16cda506bac8eeca78stephen hemminger
906861d7f745f37506bbd90227e97b95baf2a5fac34stephen hemminger	return nla_nest_end(skb, nla);
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9081e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardynla_put_failure:
909861d7f745f37506bbd90227e97b95baf2a5fac34stephen hemminger	nlmsg_trim(skb, nla);
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
91310f6dfcfde884441db89dc66b945d6c948e1d356stephen hemmingerstatic int netem_dump_class(struct Qdisc *sch, unsigned long cl,
91410f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger			  struct sk_buff *skb, struct tcmsg *tcm)
91510f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger{
91610f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	struct netem_sched_data *q = qdisc_priv(sch);
91710f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger
91850612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	if (cl != 1 || !q->qdisc) 	/* only one class */
91910f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger		return -ENOENT;
92010f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger
92110f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	tcm->tcm_handle |= TC_H_MIN(1);
92210f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	tcm->tcm_info = q->qdisc->handle;
92310f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger
92410f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	return 0;
92510f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger}
92610f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger
92710f6dfcfde884441db89dc66b945d6c948e1d356stephen hemmingerstatic int netem_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
92810f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger		     struct Qdisc **old)
92910f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger{
93010f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	struct netem_sched_data *q = qdisc_priv(sch);
93110f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger
93210f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	sch_tree_lock(sch);
93310f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	*old = q->qdisc;
93410f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	q->qdisc = new;
93550612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	if (*old) {
93650612537e9ab29693122fab20fc1eed235054ffeEric Dumazet		qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
93750612537e9ab29693122fab20fc1eed235054ffeEric Dumazet		qdisc_reset(*old);
93850612537e9ab29693122fab20fc1eed235054ffeEric Dumazet	}
93910f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	sch_tree_unlock(sch);
94010f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger
94110f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	return 0;
94210f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger}
94310f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger
94410f6dfcfde884441db89dc66b945d6c948e1d356stephen hemmingerstatic struct Qdisc *netem_leaf(struct Qdisc *sch, unsigned long arg)
94510f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger{
94610f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	struct netem_sched_data *q = qdisc_priv(sch);
94710f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	return q->qdisc;
94810f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger}
94910f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger
95010f6dfcfde884441db89dc66b945d6c948e1d356stephen hemmingerstatic unsigned long netem_get(struct Qdisc *sch, u32 classid)
95110f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger{
95210f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	return 1;
95310f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger}
95410f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger
95510f6dfcfde884441db89dc66b945d6c948e1d356stephen hemmingerstatic void netem_put(struct Qdisc *sch, unsigned long arg)
95610f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger{
95710f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger}
95810f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger
95910f6dfcfde884441db89dc66b945d6c948e1d356stephen hemmingerstatic void netem_walk(struct Qdisc *sch, struct qdisc_walker *walker)
96010f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger{
96110f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	if (!walker->stop) {
96210f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger		if (walker->count >= walker->skip)
96310f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger			if (walker->fn(sch, 1, walker) < 0) {
96410f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger				walker->stop = 1;
96510f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger				return;
96610f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger			}
96710f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger		walker->count++;
96810f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	}
96910f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger}
97010f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger
97110f6dfcfde884441db89dc66b945d6c948e1d356stephen hemmingerstatic const struct Qdisc_class_ops netem_class_ops = {
97210f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	.graft		=	netem_graft,
97310f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	.leaf		=	netem_leaf,
97410f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	.get		=	netem_get,
97510f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	.put		=	netem_put,
97610f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	.walk		=	netem_walk,
97710f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	.dump		=	netem_dump_class,
97810f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger};
97910f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger
98020fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazetstatic struct Qdisc_ops netem_qdisc_ops __read_mostly = {
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.id		=	"netem",
98210f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger	.cl_ops		=	&netem_class_ops,
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.priv_size	=	sizeof(struct netem_sched_data),
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.enqueue	=	netem_enqueue,
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.dequeue	=	netem_dequeue,
98677be155cba4e163e8bba9fd27222a8b6189ec4f7Jarek Poplawski	.peek		=	qdisc_peek_dequeued,
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.drop		=	netem_drop,
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.init		=	netem_init,
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.reset		=	netem_reset,
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.destroy	=	netem_destroy,
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.change		=	netem_change,
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.dump		=	netem_dump,
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner		=	THIS_MODULE,
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init netem_module_init(void)
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
999eb229c4cdc3389682cda20adb015ba767950a220Stephen Hemminger	pr_info("netem: version " VERSION "\n");
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return register_qdisc(&netem_qdisc_ops);
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit netem_module_exit(void)
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unregister_qdisc(&netem_qdisc_ops);
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(netem_module_init)
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(netem_module_exit)
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
1009