sch_netem.c revision 809fa972fd90ff27225294b17a027e908b2d7b7a
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> 26aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet#include <linux/rbtree.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28dc5fc579b90ed0a9a4e55b0218cdbaf0a8cf2e67Arnaldo Carvalho de Melo#include <net/netlink.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/pkt_sched.h> 30e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet#include <net/inet_ecn.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32250a65f78265940ac33a2dd2002924e6126efe14stephen hemminger#define VERSION "1.3" 33eb229c4cdc3389682cda20adb015ba767950a220Stephen Hemminger 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Network Emulation Queuing algorithm. 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ==================================== 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Sources: [1] Mark Carson, Darrin Santay, "NIST Net - A Linux-based 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Network Emulation Tool 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds [2] Luigi Rizzo, DummyNet for FreeBSD 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ---------------------------------------------------------------- 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This started out as a simple way to delay outgoing packets to 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds test TCP but has grown to include most of the functionality 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds of a full blown network emulator like NISTnet. It can delay 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds packets and add random jitter (and correlation). The random 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds distribution can be loaded from a table as well to provide 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds normal, Pareto, or experimental curves. Packet loss, 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds duplication, and reordering can also be emulated. 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This qdisc does not do classification that can be handled in 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds layering other disciplines. It does not need to do bandwidth 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds control either since that can be handled by using token 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bucket or other rate control. 55661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 56661b79725fea030803a89a16cda506bac8eeca78stephen hemminger Correlated Loss Generator models 57661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 58661b79725fea030803a89a16cda506bac8eeca78stephen hemminger Added generation of correlated loss according to the 59661b79725fea030803a89a16cda506bac8eeca78stephen hemminger "Gilbert-Elliot" model, a 4-state markov model. 60661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 61661b79725fea030803a89a16cda506bac8eeca78stephen hemminger References: 62661b79725fea030803a89a16cda506bac8eeca78stephen hemminger [1] NetemCLG Home http://netgroup.uniroma2.it/NetemCLG 63661b79725fea030803a89a16cda506bac8eeca78stephen hemminger [2] S. Salsano, F. Ludovici, A. Ordine, "Definition of a general 64661b79725fea030803a89a16cda506bac8eeca78stephen hemminger and intuitive loss model for packet networks and its implementation 65661b79725fea030803a89a16cda506bac8eeca78stephen hemminger in the Netem module in the Linux kernel", available in [1] 66661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 67661b79725fea030803a89a16cda506bac8eeca78stephen hemminger Authors: Stefano Salsano <stefano.salsano at uniroma2.it 68661b79725fea030803a89a16cda506bac8eeca78stephen hemminger Fabio Ludovici <fabio.ludovici at yahoo.it> 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct netem_sched_data { 72aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet /* internal t(ime)fifo qdisc uses t_root and sch->limit */ 73aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet struct rb_root t_root; 7450612537e9ab29693122fab20fc1eed235054ffeEric Dumazet 7550612537e9ab29693122fab20fc1eed235054ffeEric Dumazet /* optional qdisc for classful handling (NULL at netem init) */ 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct Qdisc *qdisc; 7750612537e9ab29693122fab20fc1eed235054ffeEric Dumazet 7859cb5c6734021acc68590c7c2e0e92ad9a4952c6Patrick McHardy struct qdisc_watchdog watchdog; 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 80b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger psched_tdiff_t latency; 81b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger psched_tdiff_t jitter; 82b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 loss; 84e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet u32 ecn; 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 limit; 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 counter; 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 gap; 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 duplicate; 890dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger u32 reorder; 90c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger u32 corrupt; 916a031f67c83aa175aedd10d4ae64750415ab57b0Yang Yingliang u64 rate; 9290b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer s32 packet_overhead; 9390b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer u32 cell_size; 94809fa972fd90ff27225294b17a027e908b2d7b7aHannes Frederic Sowa struct reciprocal_value cell_size_reciprocal; 9590b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer s32 cell_overhead; 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct crndstate { 98b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger u32 last; 99b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger u32 rho; 100c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger } delay_cor, loss_cor, dup_cor, reorder_cor, corrupt_cor; 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct disttable { 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 size; 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s16 table[0]; 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } *delay_dist; 106661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 107661b79725fea030803a89a16cda506bac8eeca78stephen hemminger enum { 108661b79725fea030803a89a16cda506bac8eeca78stephen hemminger CLG_RANDOM, 109661b79725fea030803a89a16cda506bac8eeca78stephen hemminger CLG_4_STATES, 110661b79725fea030803a89a16cda506bac8eeca78stephen hemminger CLG_GILB_ELL, 111661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } loss_model; 112661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 113a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang enum { 114a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang TX_IN_GAP_PERIOD = 1, 115a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang TX_IN_BURST_PERIOD, 116a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang LOST_IN_GAP_PERIOD, 117a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang LOST_IN_BURST_PERIOD, 118a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang } _4_state_model; 119a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang 120661b79725fea030803a89a16cda506bac8eeca78stephen hemminger /* Correlated Loss Generation models */ 121661b79725fea030803a89a16cda506bac8eeca78stephen hemminger struct clgstate { 122661b79725fea030803a89a16cda506bac8eeca78stephen hemminger /* state of the Markov chain */ 123661b79725fea030803a89a16cda506bac8eeca78stephen hemminger u8 state; 124661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 125661b79725fea030803a89a16cda506bac8eeca78stephen hemminger /* 4-states and Gilbert-Elliot models */ 126661b79725fea030803a89a16cda506bac8eeca78stephen hemminger u32 a1; /* p13 for 4-states or p for GE */ 127661b79725fea030803a89a16cda506bac8eeca78stephen hemminger u32 a2; /* p31 for 4-states or r for GE */ 128661b79725fea030803a89a16cda506bac8eeca78stephen hemminger u32 a3; /* p32 for 4-states or h for GE */ 129661b79725fea030803a89a16cda506bac8eeca78stephen hemminger u32 a4; /* p14 for 4-states or 1-k for GE */ 130661b79725fea030803a89a16cda506bac8eeca78stephen hemminger u32 a5; /* p23 used only in 4-states */ 131661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } clg; 132661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13550612537e9ab29693122fab20fc1eed235054ffeEric Dumazet/* Time stamp put into socket buffer control block 13650612537e9ab29693122fab20fc1eed235054ffeEric Dumazet * Only valid when skbs are in our internal t(ime)fifo queue. 13750612537e9ab29693122fab20fc1eed235054ffeEric Dumazet */ 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct netem_skb_cb { 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psched_time_t time_to_send; 140aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet ktime_t tstamp_save; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 143aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet/* Because space in skb->cb[] is tight, netem overloads skb->next/prev/tstamp 144aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet * to hold a rb_node structure. 145aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet * 146aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet * If struct sk_buff layout is changed, the following checks will complain. 147aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet */ 148aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazetstatic struct rb_node *netem_rb_node(struct sk_buff *skb) 149aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet{ 150aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet BUILD_BUG_ON(offsetof(struct sk_buff, next) != 0); 151aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet BUILD_BUG_ON(offsetof(struct sk_buff, prev) != 152aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet offsetof(struct sk_buff, next) + sizeof(skb->next)); 153aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet BUILD_BUG_ON(offsetof(struct sk_buff, tstamp) != 154aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet offsetof(struct sk_buff, prev) + sizeof(skb->prev)); 155aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet BUILD_BUG_ON(sizeof(struct rb_node) > sizeof(skb->next) + 156aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet sizeof(skb->prev) + 157aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet sizeof(skb->tstamp)); 158aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet return (struct rb_node *)&skb->next; 159aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet} 160aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet 161aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazetstatic struct sk_buff *netem_rb_to_skb(struct rb_node *rb) 162aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet{ 163aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet return (struct sk_buff *)rb; 164aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet} 165aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet 1665f86173bdf15981ca49d0434f638b68f70a35644Jussi Kivilinnastatic inline struct netem_skb_cb *netem_skb_cb(struct sk_buff *skb) 1675f86173bdf15981ca49d0434f638b68f70a35644Jussi Kivilinna{ 168aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet /* we assume we can use skb next/prev/tstamp as storage for rb_node */ 16916bda13d90c8d5da243e2cfa1677e62ecce26860David S. Miller qdisc_cb_private_validate(skb, sizeof(struct netem_skb_cb)); 170175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return (struct netem_skb_cb *)qdisc_skb_cb(skb)->data; 1715f86173bdf15981ca49d0434f638b68f70a35644Jussi Kivilinna} 1725f86173bdf15981ca49d0434f638b68f70a35644Jussi Kivilinna 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* init_crandom - initialize correlated random number generator 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Use entropy source for initial seed. 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void init_crandom(struct crndstate *state, unsigned long rho) 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds state->rho = rho; 17963862b5bef7349dd1137e4c70702c67d77565785Aruna-Hewapathirane state->last = prandom_u32(); 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* get_crandom - correlated random number generator 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Next number depends on last value. 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * rho is scaled to avoid floating point. 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 186b407621c35ed5f9a0734e57472e9539117963768Stephen Hemmingerstatic u32 get_crandom(struct crndstate *state) 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u64 value, rho; 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long answer; 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 191bb2f8cc0ecf025d6d3947e0389434650023f432eStephen Hemminger if (state->rho == 0) /* no correlation */ 19263862b5bef7349dd1137e4c70702c67d77565785Aruna-Hewapathirane return prandom_u32(); 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19463862b5bef7349dd1137e4c70702c67d77565785Aruna-Hewapathirane value = prandom_u32(); 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rho = (u64)state->rho + 1; 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds answer = (value * ((1ull<<32) - rho) + state->last * rho) >> 32; 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds state->last = answer; 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return answer; 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 201661b79725fea030803a89a16cda506bac8eeca78stephen hemminger/* loss_4state - 4-state model loss generator 202661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * Generates losses according to the 4-state Markov chain adopted in 203661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * the GI (General and Intuitive) loss model. 204661b79725fea030803a89a16cda506bac8eeca78stephen hemminger */ 205661b79725fea030803a89a16cda506bac8eeca78stephen hemmingerstatic bool loss_4state(struct netem_sched_data *q) 206661b79725fea030803a89a16cda506bac8eeca78stephen hemminger{ 207661b79725fea030803a89a16cda506bac8eeca78stephen hemminger struct clgstate *clg = &q->clg; 20863862b5bef7349dd1137e4c70702c67d77565785Aruna-Hewapathirane u32 rnd = prandom_u32(); 209661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 210661b79725fea030803a89a16cda506bac8eeca78stephen hemminger /* 21125985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * Makes a comparison between rnd and the transition 212661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * probabilities outgoing from the current state, then decides the 213661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * next state and if the next packet has to be transmitted or lost. 214661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * The four states correspond to: 215a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang * TX_IN_GAP_PERIOD => successfully transmitted packets within a gap period 216a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang * LOST_IN_BURST_PERIOD => isolated losses within a gap period 217a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang * LOST_IN_GAP_PERIOD => lost packets within a burst period 218a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang * TX_IN_GAP_PERIOD => successfully transmitted packets within a burst period 219661b79725fea030803a89a16cda506bac8eeca78stephen hemminger */ 220661b79725fea030803a89a16cda506bac8eeca78stephen hemminger switch (clg->state) { 221a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang case TX_IN_GAP_PERIOD: 222661b79725fea030803a89a16cda506bac8eeca78stephen hemminger if (rnd < clg->a4) { 223a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang clg->state = LOST_IN_BURST_PERIOD; 224661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return true; 225ab6c27be8178a4682446faa5aa017b948997937fstephen hemminger } else if (clg->a4 < rnd && rnd < clg->a1 + clg->a4) { 226a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang clg->state = LOST_IN_GAP_PERIOD; 227661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return true; 228a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang } else if (clg->a1 + clg->a4 < rnd) { 229a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang clg->state = TX_IN_GAP_PERIOD; 230a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang } 231661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 232661b79725fea030803a89a16cda506bac8eeca78stephen hemminger break; 233a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang case TX_IN_BURST_PERIOD: 234661b79725fea030803a89a16cda506bac8eeca78stephen hemminger if (rnd < clg->a5) { 235a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang clg->state = LOST_IN_GAP_PERIOD; 236661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return true; 237a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang } else { 238a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang clg->state = TX_IN_BURST_PERIOD; 239a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang } 240661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 241661b79725fea030803a89a16cda506bac8eeca78stephen hemminger break; 242a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang case LOST_IN_GAP_PERIOD: 243661b79725fea030803a89a16cda506bac8eeca78stephen hemminger if (rnd < clg->a3) 244a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang clg->state = TX_IN_BURST_PERIOD; 245661b79725fea030803a89a16cda506bac8eeca78stephen hemminger else if (clg->a3 < rnd && rnd < clg->a2 + clg->a3) { 246a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang clg->state = TX_IN_GAP_PERIOD; 247661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } else if (clg->a2 + clg->a3 < rnd) { 248a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang clg->state = LOST_IN_GAP_PERIOD; 249661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return true; 250661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } 251661b79725fea030803a89a16cda506bac8eeca78stephen hemminger break; 252a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang case LOST_IN_BURST_PERIOD: 253a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang clg->state = TX_IN_GAP_PERIOD; 254661b79725fea030803a89a16cda506bac8eeca78stephen hemminger break; 255661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } 256661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 257661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return false; 258661b79725fea030803a89a16cda506bac8eeca78stephen hemminger} 259661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 260661b79725fea030803a89a16cda506bac8eeca78stephen hemminger/* loss_gilb_ell - Gilbert-Elliot model loss generator 261661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * Generates losses according to the Gilbert-Elliot loss model or 262661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * its special cases (Gilbert or Simple Gilbert) 263661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * 26425985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * Makes a comparison between random number and the transition 265661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * probabilities outgoing from the current state, then decides the 26625985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * next state. A second random number is extracted and the comparison 267661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * with the loss probability of the current state decides if the next 268661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * packet will be transmitted or lost. 269661b79725fea030803a89a16cda506bac8eeca78stephen hemminger */ 270661b79725fea030803a89a16cda506bac8eeca78stephen hemmingerstatic bool loss_gilb_ell(struct netem_sched_data *q) 271661b79725fea030803a89a16cda506bac8eeca78stephen hemminger{ 272661b79725fea030803a89a16cda506bac8eeca78stephen hemminger struct clgstate *clg = &q->clg; 273661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 274661b79725fea030803a89a16cda506bac8eeca78stephen hemminger switch (clg->state) { 275661b79725fea030803a89a16cda506bac8eeca78stephen hemminger case 1: 27663862b5bef7349dd1137e4c70702c67d77565785Aruna-Hewapathirane if (prandom_u32() < clg->a1) 277661b79725fea030803a89a16cda506bac8eeca78stephen hemminger clg->state = 2; 27863862b5bef7349dd1137e4c70702c67d77565785Aruna-Hewapathirane if (prandom_u32() < clg->a4) 279661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return true; 2807c2781fa92f5b9ca3188817a56a2ced0400355f3stephen hemminger break; 281661b79725fea030803a89a16cda506bac8eeca78stephen hemminger case 2: 28263862b5bef7349dd1137e4c70702c67d77565785Aruna-Hewapathirane if (prandom_u32() < clg->a2) 283661b79725fea030803a89a16cda506bac8eeca78stephen hemminger clg->state = 1; 28463862b5bef7349dd1137e4c70702c67d77565785Aruna-Hewapathirane if (prandom_u32() > clg->a3) 285661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return true; 286661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } 287661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 288661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return false; 289661b79725fea030803a89a16cda506bac8eeca78stephen hemminger} 290661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 291661b79725fea030803a89a16cda506bac8eeca78stephen hemmingerstatic bool loss_event(struct netem_sched_data *q) 292661b79725fea030803a89a16cda506bac8eeca78stephen hemminger{ 293661b79725fea030803a89a16cda506bac8eeca78stephen hemminger switch (q->loss_model) { 294661b79725fea030803a89a16cda506bac8eeca78stephen hemminger case CLG_RANDOM: 295661b79725fea030803a89a16cda506bac8eeca78stephen hemminger /* Random packet drop 0 => none, ~0 => all */ 296661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return q->loss && q->loss >= get_crandom(&q->loss_cor); 297661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 298661b79725fea030803a89a16cda506bac8eeca78stephen hemminger case CLG_4_STATES: 299661b79725fea030803a89a16cda506bac8eeca78stephen hemminger /* 4state loss model algorithm (used also for GI model) 300661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * Extracts a value from the markov 4 state loss generator, 301661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * if it is 1 drops a packet and if needed writes the event in 302661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * the kernel logs 303661b79725fea030803a89a16cda506bac8eeca78stephen hemminger */ 304661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return loss_4state(q); 305661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 306661b79725fea030803a89a16cda506bac8eeca78stephen hemminger case CLG_GILB_ELL: 307661b79725fea030803a89a16cda506bac8eeca78stephen hemminger /* Gilbert-Elliot loss model algorithm 308661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * Extracts a value from the Gilbert-Elliot loss generator, 309661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * if it is 1 drops a packet and if needed writes the event in 310661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * the kernel logs 311661b79725fea030803a89a16cda506bac8eeca78stephen hemminger */ 312661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return loss_gilb_ell(q); 313661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } 314661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 315661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return false; /* not reached */ 316661b79725fea030803a89a16cda506bac8eeca78stephen hemminger} 317661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 318661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* tabledist - return a pseudo-randomly distributed value with mean mu and 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * std deviation sigma. Uses table lookup to approximate the desired 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * distribution, and a uniformly-distributed pseudo-random source. 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 323b407621c35ed5f9a0734e57472e9539117963768Stephen Hemmingerstatic psched_tdiff_t tabledist(psched_tdiff_t mu, psched_tdiff_t sigma, 324b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger struct crndstate *state, 325b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger const struct disttable *dist) 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 327b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger psched_tdiff_t x; 328b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger long t; 329b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger u32 rnd; 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sigma == 0) 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return mu; 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rnd = get_crandom(state); 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* default uniform distribution */ 33710297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki if (dist == NULL) 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (rnd % (2*sigma)) - sigma + mu; 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds t = dist->table[rnd % dist->size]; 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds x = (sigma % NETEM_DIST_SCALE) * t; 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (x >= 0) 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds x += NETEM_DIST_SCALE/2; 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds x -= NETEM_DIST_SCALE/2; 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return x / NETEM_DIST_SCALE + (sigma / NETEM_DIST_SCALE) * t + mu; 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35090b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeiferstatic psched_time_t packet_len_2_sched_time(unsigned int len, struct netem_sched_data *q) 3517bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer{ 35290b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer u64 ticks; 353fc33cc72423ed3474cd51bc8bd7c1cdc22a78e1aEric Dumazet 35490b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer len += q->packet_overhead; 35590b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer 35690b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer if (q->cell_size) { 35790b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer u32 cells = reciprocal_divide(len, q->cell_size_reciprocal); 35890b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer 35990b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer if (len > cells * q->cell_size) /* extra cell needed for remainder */ 36090b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer cells++; 36190b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer len = cells * (q->cell_size + q->cell_overhead); 36290b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer } 36390b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer 36490b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer ticks = (u64)len * NSEC_PER_SEC; 36590b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer 36690b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer do_div(ticks, q->rate); 367fc33cc72423ed3474cd51bc8bd7c1cdc22a78e1aEric Dumazet return PSCHED_NS2TICKS(ticks); 3687bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer} 3697bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer 370ff704050f2fc0f3382b5a70bba56a51a3feca79dstephen hemmingerstatic void tfifo_reset(struct Qdisc *sch) 371ff704050f2fc0f3382b5a70bba56a51a3feca79dstephen hemminger{ 372ff704050f2fc0f3382b5a70bba56a51a3feca79dstephen hemminger struct netem_sched_data *q = qdisc_priv(sch); 373ff704050f2fc0f3382b5a70bba56a51a3feca79dstephen hemminger struct rb_node *p; 374ff704050f2fc0f3382b5a70bba56a51a3feca79dstephen hemminger 375ff704050f2fc0f3382b5a70bba56a51a3feca79dstephen hemminger while ((p = rb_first(&q->t_root))) { 376ff704050f2fc0f3382b5a70bba56a51a3feca79dstephen hemminger struct sk_buff *skb = netem_rb_to_skb(p); 377ff704050f2fc0f3382b5a70bba56a51a3feca79dstephen hemminger 378ff704050f2fc0f3382b5a70bba56a51a3feca79dstephen hemminger rb_erase(p, &q->t_root); 379ff704050f2fc0f3382b5a70bba56a51a3feca79dstephen hemminger skb->next = NULL; 380ff704050f2fc0f3382b5a70bba56a51a3feca79dstephen hemminger skb->prev = NULL; 381ff704050f2fc0f3382b5a70bba56a51a3feca79dstephen hemminger kfree_skb(skb); 382ff704050f2fc0f3382b5a70bba56a51a3feca79dstephen hemminger } 383ff704050f2fc0f3382b5a70bba56a51a3feca79dstephen hemminger} 384ff704050f2fc0f3382b5a70bba56a51a3feca79dstephen hemminger 385960fb66e520a405dde39ff883f17ff2669c13d85Eric Dumazetstatic void tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch) 38650612537e9ab29693122fab20fc1eed235054ffeEric Dumazet{ 387aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet struct netem_sched_data *q = qdisc_priv(sch); 38850612537e9ab29693122fab20fc1eed235054ffeEric Dumazet psched_time_t tnext = netem_skb_cb(nskb)->time_to_send; 389aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet struct rb_node **p = &q->t_root.rb_node, *parent = NULL; 39050612537e9ab29693122fab20fc1eed235054ffeEric Dumazet 391aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet while (*p) { 392aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet struct sk_buff *skb; 39350612537e9ab29693122fab20fc1eed235054ffeEric Dumazet 394aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet parent = *p; 395aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet skb = netem_rb_to_skb(parent); 396960fb66e520a405dde39ff883f17ff2669c13d85Eric Dumazet if (tnext >= netem_skb_cb(skb)->time_to_send) 397aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet p = &parent->rb_right; 398aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet else 399aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet p = &parent->rb_left; 40050612537e9ab29693122fab20fc1eed235054ffeEric Dumazet } 401aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet rb_link_node(netem_rb_node(nskb), parent, p); 402aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet rb_insert_color(netem_rb_node(nskb), &q->t_root); 403aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet sch->q.qlen++; 40450612537e9ab29693122fab20fc1eed235054ffeEric Dumazet} 40550612537e9ab29693122fab20fc1eed235054ffeEric Dumazet 4060afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger/* 4070afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger * Insert one skb into qdisc. 4080afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger * Note: parent depends on return value to account for queue length. 4090afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger * NET_XMIT_DROP: queue length didn't change. 4100afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger * NET_XMIT_SUCCESS: one skb was queued. 4110afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger */ 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct netem_sched_data *q = qdisc_priv(sch); 41589e1df74f841fc31e81838d30594c4eff01859f8Guillaume Chazarain /* We don't fill cb now as skb_unshare() may invalidate it */ 41689e1df74f841fc31e81838d30594c4eff01859f8Guillaume Chazarain struct netem_skb_cb *cb; 4170afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger struct sk_buff *skb2; 4180afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger int count = 1; 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4200afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger /* Random duplication */ 4210afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger if (q->duplicate && q->duplicate >= get_crandom(&q->dup_cor)) 4220afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger ++count; 4230afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger 424661b79725fea030803a89a16cda506bac8eeca78stephen hemminger /* Drop packet? */ 425e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet if (loss_event(q)) { 426e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet if (q->ecn && INET_ECN_set_ce(skb)) 427e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet sch->qstats.drops++; /* mark packet */ 428e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet else 429e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet --count; 430e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet } 4310afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger if (count == 0) { 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sch->qstats.drops++; 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree_skb(skb); 434c27f339af90bb874a7a9c680b17abfd32d4a727bJarek Poplawski return NET_XMIT_SUCCESS | __NET_XMIT_BYPASS; 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4375a308f40bfe27fcfd1db3970afe18b635f23c182Eric Dumazet /* If a delay is expected, orphan the skb. (orphaning usually takes 4385a308f40bfe27fcfd1db3970afe18b635f23c182Eric Dumazet * place at TX completion time, so _before_ the link transit delay) 4395a308f40bfe27fcfd1db3970afe18b635f23c182Eric Dumazet */ 4405a308f40bfe27fcfd1db3970afe18b635f23c182Eric Dumazet if (q->latency || q->jitter) 441f2f872f9272a79a1048877ea14c15576f46c225eEric Dumazet skb_orphan_partial(skb); 4424e8a5201506423e0241202de1349422af4260296David S. Miller 4430afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger /* 4440afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger * If we need to duplicate packet, then re-insert at top of the 4450afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger * qdisc tree, since parent queuer expects that only one 4460afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger * skb will be queued. 4470afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger */ 4480afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger if (count > 1 && (skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) { 4497698b4fcabcd790efc4f226bada1e7b5870653afDavid S. Miller struct Qdisc *rootq = qdisc_root(sch); 4500afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger u32 dupsave = q->duplicate; /* prevent duplicating a dup... */ 4510afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger q->duplicate = 0; 4520afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger 4535f86173bdf15981ca49d0434f638b68f70a35644Jussi Kivilinna qdisc_enqueue_root(skb2, rootq); 4540afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger q->duplicate = dupsave; 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 457c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger /* 458c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger * Randomized packet corruption. 459c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger * Make copy if needed since we are modifying 460c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger * If packet is going to be hardware checksummed, then 461c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger * do it now in software before we mangle it. 462c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger */ 463c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger if (q->corrupt && q->corrupt >= get_crandom(&q->corrupt_cor)) { 464f64f9e719261a87818dd192a3a2352e5b20fbd0fJoe Perches if (!(skb = skb_unshare(skb, GFP_ATOMIC)) || 465f64f9e719261a87818dd192a3a2352e5b20fbd0fJoe Perches (skb->ip_summed == CHECKSUM_PARTIAL && 466116a0fc31c6c9b8fc821be5a96e5bf0b43260131Eric Dumazet skb_checksum_help(skb))) 467116a0fc31c6c9b8fc821be5a96e5bf0b43260131Eric Dumazet return qdisc_drop(skb, sch); 468c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger 46963862b5bef7349dd1137e4c70702c67d77565785Aruna-Hewapathirane skb->data[prandom_u32() % skb_headlen(skb)] ^= 47063862b5bef7349dd1137e4c70702c67d77565785Aruna-Hewapathirane 1<<(prandom_u32() % 8); 471c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger } 472c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger 473960fb66e520a405dde39ff883f17ff2669c13d85Eric Dumazet if (unlikely(skb_queue_len(&sch->q) >= sch->limit)) 474960fb66e520a405dde39ff883f17ff2669c13d85Eric Dumazet return qdisc_reshape_fail(skb, sch); 475960fb66e520a405dde39ff883f17ff2669c13d85Eric Dumazet 476960fb66e520a405dde39ff883f17ff2669c13d85Eric Dumazet sch->qstats.backlog += qdisc_pkt_len(skb); 477960fb66e520a405dde39ff883f17ff2669c13d85Eric Dumazet 4785f86173bdf15981ca49d0434f638b68f70a35644Jussi Kivilinna cb = netem_skb_cb(skb); 479cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (q->gap == 0 || /* not doing reordering */ 480a42b4799c683723e8c464de4026af085b2ebd5faVijay Subramanian q->counter < q->gap - 1 || /* inside last reordering gap */ 481f64f9e719261a87818dd192a3a2352e5b20fbd0fJoe Perches q->reorder < get_crandom(&q->reorder_cor)) { 4820f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger psched_time_t now; 48307aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger psched_tdiff_t delay; 48407aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger 48507aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger delay = tabledist(q->latency, q->jitter, 48607aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger &q->delay_cor, q->delay_dist); 48707aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger 4883bebcda28077375470dd60545b71bba2f83335fdPatrick McHardy now = psched_get_time(); 4897bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer 4907bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer if (q->rate) { 491aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet struct sk_buff *last; 4927bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer 493aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet if (!skb_queue_empty(&sch->q)) 494aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet last = skb_peek_tail(&sch->q); 495aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet else 496aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet last = netem_rb_to_skb(rb_last(&q->t_root)); 497aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet if (last) { 4987bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer /* 499a13d3104710184ecc43edc35a25ae8092058463fJohannes Naab * Last packet in queue is reference point (now), 500a13d3104710184ecc43edc35a25ae8092058463fJohannes Naab * calculate this time bonus and subtract 5017bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer * from delay. 5027bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer */ 503aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet delay -= netem_skb_cb(last)->time_to_send - now; 504a13d3104710184ecc43edc35a25ae8092058463fJohannes Naab delay = max_t(psched_tdiff_t, 0, delay); 505aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet now = netem_skb_cb(last)->time_to_send; 5067bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer } 507a13d3104710184ecc43edc35a25ae8092058463fJohannes Naab 5088cfd88d6d70735c47b17aef855b4c81dde83c85cYang Yingliang delay += packet_len_2_sched_time(qdisc_pkt_len(skb), q); 5097bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer } 5107bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer 5117c59e25f3186f26e85b13a318dbc4482d1d363e9Patrick McHardy cb->time_to_send = now + delay; 512aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet cb->tstamp_save = skb->tstamp; 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++q->counter; 514960fb66e520a405dde39ff883f17ff2669c13d85Eric Dumazet tfifo_enqueue(skb, sch); 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 51610297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki /* 5170dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger * Do re-ordering by putting one out of N packets at the front 5180dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger * of the queue. 5190dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger */ 5203bebcda28077375470dd60545b71bba2f83335fdPatrick McHardy cb->time_to_send = psched_get_time(); 5210dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger q->counter = 0; 5228ba25dad0ac78850cd46d91186a27d60f7314752Jarek Poplawski 52350612537e9ab29693122fab20fc1eed235054ffeEric Dumazet __skb_queue_head(&sch->q, skb); 524eb10192447370f19a215a8c2749332afa1199d46Hagen Paul Pfeifer sch->qstats.requeues++; 525378a2f090f7a478704a372a4869b8a9ac206234eJarek Poplawski } 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 52710f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger return NET_XMIT_SUCCESS; 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 530cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazetstatic unsigned int netem_drop(struct Qdisc *sch) 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct netem_sched_data *q = qdisc_priv(sch); 53350612537e9ab29693122fab20fc1eed235054ffeEric Dumazet unsigned int len; 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 53550612537e9ab29693122fab20fc1eed235054ffeEric Dumazet len = qdisc_queue_drop(sch); 536aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet 537aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet if (!len) { 538aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet struct rb_node *p = rb_first(&q->t_root); 539aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet 540aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet if (p) { 541aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet struct sk_buff *skb = netem_rb_to_skb(p); 542aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet 543aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet rb_erase(p, &q->t_root); 544aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet sch->q.qlen--; 545aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet skb->next = NULL; 546aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet skb->prev = NULL; 547aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet len = qdisc_pkt_len(skb); 548638a52b801e40ed276ceb69b73579ad99365361astephen hemminger sch->qstats.backlog -= len; 549aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet kfree_skb(skb); 550aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet } 551aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet } 55250612537e9ab29693122fab20fc1eed235054ffeEric Dumazet if (!len && q->qdisc && q->qdisc->ops->drop) 55350612537e9ab29693122fab20fc1eed235054ffeEric Dumazet len = q->qdisc->ops->drop(q->qdisc); 55450612537e9ab29693122fab20fc1eed235054ffeEric Dumazet if (len) 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sch->qstats.drops++; 55650612537e9ab29693122fab20fc1eed235054ffeEric Dumazet 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return len; 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sk_buff *netem_dequeue(struct Qdisc *sch) 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct netem_sched_data *q = qdisc_priv(sch); 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 564aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet struct rb_node *p; 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 566fd245a4adb5288eac37250875f237c40a20a1944Eric Dumazet if (qdisc_is_throttled(sch)) 56711274e5a43266d531140530adebead6903380cafStephen Hemminger return NULL; 56811274e5a43266d531140530adebead6903380cafStephen Hemminger 56950612537e9ab29693122fab20fc1eed235054ffeEric Dumazettfifo_dequeue: 570aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet skb = __skb_dequeue(&sch->q); 571771018e76aaa6474be20a53c20458bcae8b00485Stephen Hemminger if (skb) { 572aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazetdeliver: 573aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet sch->qstats.backlog -= qdisc_pkt_len(skb); 574aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet qdisc_unthrottled(sch); 575aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet qdisc_bstats_update(sch, skb); 576aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet return skb; 577aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet } 578aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet p = rb_first(&q->t_root); 579aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet if (p) { 58036b7bfe09b6deb71bf387852465245783c9a6208Eric Dumazet psched_time_t time_to_send; 58136b7bfe09b6deb71bf387852465245783c9a6208Eric Dumazet 582aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet skb = netem_rb_to_skb(p); 5830f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger 5840f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger /* if more time remaining? */ 58536b7bfe09b6deb71bf387852465245783c9a6208Eric Dumazet time_to_send = netem_skb_cb(skb)->time_to_send; 58636b7bfe09b6deb71bf387852465245783c9a6208Eric Dumazet if (time_to_send <= psched_get_time()) { 587aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet rb_erase(p, &q->t_root); 588aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet 589aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet sch->q.qlen--; 590aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet skb->next = NULL; 591aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet skb->prev = NULL; 592aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet skb->tstamp = netem_skb_cb(skb)->tstamp_save; 59303c05f0d4bb0c267edf12d614025a40e33c5a6f9Jarek Poplawski 5948caf153974f2274301e583fda732cc8e5b80331fJarek Poplawski#ifdef CONFIG_NET_CLS_ACT 5958caf153974f2274301e583fda732cc8e5b80331fJarek Poplawski /* 5968caf153974f2274301e583fda732cc8e5b80331fJarek Poplawski * If it's at ingress let's pretend the delay is 5978caf153974f2274301e583fda732cc8e5b80331fJarek Poplawski * from the network (tstamp will be updated). 5988caf153974f2274301e583fda732cc8e5b80331fJarek Poplawski */ 5998caf153974f2274301e583fda732cc8e5b80331fJarek Poplawski if (G_TC_FROM(skb->tc_verd) & AT_INGRESS) 6008caf153974f2274301e583fda732cc8e5b80331fJarek Poplawski skb->tstamp.tv64 = 0; 6018caf153974f2274301e583fda732cc8e5b80331fJarek Poplawski#endif 60210f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger 60350612537e9ab29693122fab20fc1eed235054ffeEric Dumazet if (q->qdisc) { 60450612537e9ab29693122fab20fc1eed235054ffeEric Dumazet int err = qdisc_enqueue(skb, q->qdisc); 60550612537e9ab29693122fab20fc1eed235054ffeEric Dumazet 60650612537e9ab29693122fab20fc1eed235054ffeEric Dumazet if (unlikely(err != NET_XMIT_SUCCESS)) { 60750612537e9ab29693122fab20fc1eed235054ffeEric Dumazet if (net_xmit_drop_count(err)) { 60850612537e9ab29693122fab20fc1eed235054ffeEric Dumazet sch->qstats.drops++; 60950612537e9ab29693122fab20fc1eed235054ffeEric Dumazet qdisc_tree_decrease_qlen(sch, 1); 61050612537e9ab29693122fab20fc1eed235054ffeEric Dumazet } 61150612537e9ab29693122fab20fc1eed235054ffeEric Dumazet } 61250612537e9ab29693122fab20fc1eed235054ffeEric Dumazet goto tfifo_dequeue; 61350612537e9ab29693122fab20fc1eed235054ffeEric Dumazet } 614aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet goto deliver; 61507aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger } 61611274e5a43266d531140530adebead6903380cafStephen Hemminger 61750612537e9ab29693122fab20fc1eed235054ffeEric Dumazet if (q->qdisc) { 61850612537e9ab29693122fab20fc1eed235054ffeEric Dumazet skb = q->qdisc->ops->dequeue(q->qdisc); 61950612537e9ab29693122fab20fc1eed235054ffeEric Dumazet if (skb) 62050612537e9ab29693122fab20fc1eed235054ffeEric Dumazet goto deliver; 62150612537e9ab29693122fab20fc1eed235054ffeEric Dumazet } 62236b7bfe09b6deb71bf387852465245783c9a6208Eric Dumazet qdisc_watchdog_schedule(&q->watchdog, time_to_send); 6230f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger } 6240f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger 62550612537e9ab29693122fab20fc1eed235054ffeEric Dumazet if (q->qdisc) { 62650612537e9ab29693122fab20fc1eed235054ffeEric Dumazet skb = q->qdisc->ops->dequeue(q->qdisc); 62750612537e9ab29693122fab20fc1eed235054ffeEric Dumazet if (skb) 62850612537e9ab29693122fab20fc1eed235054ffeEric Dumazet goto deliver; 62950612537e9ab29693122fab20fc1eed235054ffeEric Dumazet } 6300f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger return NULL; 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void netem_reset(struct Qdisc *sch) 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct netem_sched_data *q = qdisc_priv(sch); 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 63750612537e9ab29693122fab20fc1eed235054ffeEric Dumazet qdisc_reset_queue(sch); 638ff704050f2fc0f3382b5a70bba56a51a3feca79dstephen hemminger tfifo_reset(sch); 63950612537e9ab29693122fab20fc1eed235054ffeEric Dumazet if (q->qdisc) 64050612537e9ab29693122fab20fc1eed235054ffeEric Dumazet qdisc_reset(q->qdisc); 64159cb5c6734021acc68590c7c2e0e92ad9a4952c6Patrick McHardy qdisc_watchdog_cancel(&q->watchdog); 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6446373a9a286bdd955a76924cee88a2f8f784988b1stephen hemmingerstatic void dist_free(struct disttable *d) 6456373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger{ 6466373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger if (d) { 6476373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger if (is_vmalloc_addr(d)) 6486373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger vfree(d); 6496373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger else 6506373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger kfree(d); 6516373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger } 6526373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger} 6536373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Distribution data is a variable size payload containing 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * signed 16 bit values. 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6581e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardystatic int get_dist_table(struct Qdisc *sch, const struct nlattr *attr) 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct netem_sched_data *q = qdisc_priv(sch); 6616373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger size_t n = nla_len(attr)/sizeof(__s16); 6621e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy const __s16 *data = nla_data(attr); 6637698b4fcabcd790efc4f226bada1e7b5870653afDavid S. Miller spinlock_t *root_lock; 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct disttable *d; 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 6666373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger size_t s; 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 668df173bda2639ac744ccf596ec1f8f7e66fe4c343stephen hemminger if (n > NETEM_DIST_MAX) 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6716373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger s = sizeof(struct disttable) + n * sizeof(s16); 672bb52c7acf871537a468433775151339f783d2e8cEric Dumazet d = kmalloc(s, GFP_KERNEL | __GFP_NOWARN); 6736373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger if (!d) 6746373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger d = vmalloc(s); 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!d) 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds d->size = n; 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < n; i++) 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds d->table[i] = data[i]; 68110297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki 682102396ae65108b026e4e1868e30fa013f45a169eJarek Poplawski root_lock = qdisc_root_sleeping_lock(sch); 6837698b4fcabcd790efc4f226bada1e7b5870653afDavid S. Miller 6847698b4fcabcd790efc4f226bada1e7b5870653afDavid S. Miller spin_lock_bh(root_lock); 685bb52c7acf871537a468433775151339f783d2e8cEric Dumazet swap(q->delay_dist, d); 6867698b4fcabcd790efc4f226bada1e7b5870653afDavid S. Miller spin_unlock_bh(root_lock); 687bb52c7acf871537a468433775151339f783d2e8cEric Dumazet 688bb52c7acf871537a468433775151339f783d2e8cEric Dumazet dist_free(d); 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 692265eb67fb4e16be8e46a51e1e4e2ecd99fb15219Stephen Hemmingerstatic void get_correlation(struct Qdisc *sch, const struct nlattr *attr) 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct netem_sched_data *q = qdisc_priv(sch); 6951e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy const struct tc_netem_corr *c = nla_data(attr); 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_crandom(&q->delay_cor, c->delay_corr); 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_crandom(&q->loss_cor, c->loss_corr); 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_crandom(&q->dup_cor, c->dup_corr); 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 702265eb67fb4e16be8e46a51e1e4e2ecd99fb15219Stephen Hemmingerstatic void get_reorder(struct Qdisc *sch, const struct nlattr *attr) 7030dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger{ 7040dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger struct netem_sched_data *q = qdisc_priv(sch); 7051e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy const struct tc_netem_reorder *r = nla_data(attr); 7060dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger 7070dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger q->reorder = r->probability; 7080dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger init_crandom(&q->reorder_cor, r->correlation); 7090dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger} 7100dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger 711265eb67fb4e16be8e46a51e1e4e2ecd99fb15219Stephen Hemmingerstatic void get_corrupt(struct Qdisc *sch, const struct nlattr *attr) 712c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger{ 713c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger struct netem_sched_data *q = qdisc_priv(sch); 7141e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy const struct tc_netem_corrupt *r = nla_data(attr); 715c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger 716c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger q->corrupt = r->probability; 717c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger init_crandom(&q->corrupt_cor, r->correlation); 718c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger} 719c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger 7207bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeiferstatic void get_rate(struct Qdisc *sch, const struct nlattr *attr) 7217bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer{ 7227bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer struct netem_sched_data *q = qdisc_priv(sch); 7237bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer const struct tc_netem_rate *r = nla_data(attr); 7247bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer 7257bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer q->rate = r->rate; 72690b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer q->packet_overhead = r->packet_overhead; 72790b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer q->cell_size = r->cell_size; 728809fa972fd90ff27225294b17a027e908b2d7b7aHannes Frederic Sowa q->cell_overhead = r->cell_overhead; 72990b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer if (q->cell_size) 73090b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer q->cell_size_reciprocal = reciprocal_value(q->cell_size); 731809fa972fd90ff27225294b17a027e908b2d7b7aHannes Frederic Sowa else 732809fa972fd90ff27225294b17a027e908b2d7b7aHannes Frederic Sowa q->cell_size_reciprocal = (struct reciprocal_value) { 0 }; 7337bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer} 7347bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer 735661b79725fea030803a89a16cda506bac8eeca78stephen hemmingerstatic int get_loss_clg(struct Qdisc *sch, const struct nlattr *attr) 736661b79725fea030803a89a16cda506bac8eeca78stephen hemminger{ 737661b79725fea030803a89a16cda506bac8eeca78stephen hemminger struct netem_sched_data *q = qdisc_priv(sch); 738661b79725fea030803a89a16cda506bac8eeca78stephen hemminger const struct nlattr *la; 739661b79725fea030803a89a16cda506bac8eeca78stephen hemminger int rem; 740661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 741661b79725fea030803a89a16cda506bac8eeca78stephen hemminger nla_for_each_nested(la, attr, rem) { 742661b79725fea030803a89a16cda506bac8eeca78stephen hemminger u16 type = nla_type(la); 743661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 744833fa7438659d768f0aee862aab4a30cde362bbfYang Yingliang switch (type) { 745661b79725fea030803a89a16cda506bac8eeca78stephen hemminger case NETEM_LOSS_GI: { 746661b79725fea030803a89a16cda506bac8eeca78stephen hemminger const struct tc_netem_gimodel *gi = nla_data(la); 747661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 7482494654d4890316e7340fb8b3458daad0474a1b9stephen hemminger if (nla_len(la) < sizeof(struct tc_netem_gimodel)) { 749661b79725fea030803a89a16cda506bac8eeca78stephen hemminger pr_info("netem: incorrect gi model size\n"); 750661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return -EINVAL; 751661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } 752661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 753661b79725fea030803a89a16cda506bac8eeca78stephen hemminger q->loss_model = CLG_4_STATES; 754661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 755661b79725fea030803a89a16cda506bac8eeca78stephen hemminger q->clg.state = 1; 756661b79725fea030803a89a16cda506bac8eeca78stephen hemminger q->clg.a1 = gi->p13; 757661b79725fea030803a89a16cda506bac8eeca78stephen hemminger q->clg.a2 = gi->p31; 758661b79725fea030803a89a16cda506bac8eeca78stephen hemminger q->clg.a3 = gi->p32; 759661b79725fea030803a89a16cda506bac8eeca78stephen hemminger q->clg.a4 = gi->p14; 760661b79725fea030803a89a16cda506bac8eeca78stephen hemminger q->clg.a5 = gi->p23; 761661b79725fea030803a89a16cda506bac8eeca78stephen hemminger break; 762661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } 763661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 764661b79725fea030803a89a16cda506bac8eeca78stephen hemminger case NETEM_LOSS_GE: { 765661b79725fea030803a89a16cda506bac8eeca78stephen hemminger const struct tc_netem_gemodel *ge = nla_data(la); 766661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 7672494654d4890316e7340fb8b3458daad0474a1b9stephen hemminger if (nla_len(la) < sizeof(struct tc_netem_gemodel)) { 7682494654d4890316e7340fb8b3458daad0474a1b9stephen hemminger pr_info("netem: incorrect ge model size\n"); 769661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return -EINVAL; 770661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } 771661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 772661b79725fea030803a89a16cda506bac8eeca78stephen hemminger q->loss_model = CLG_GILB_ELL; 773661b79725fea030803a89a16cda506bac8eeca78stephen hemminger q->clg.state = 1; 774661b79725fea030803a89a16cda506bac8eeca78stephen hemminger q->clg.a1 = ge->p; 775661b79725fea030803a89a16cda506bac8eeca78stephen hemminger q->clg.a2 = ge->r; 776661b79725fea030803a89a16cda506bac8eeca78stephen hemminger q->clg.a3 = ge->h; 777661b79725fea030803a89a16cda506bac8eeca78stephen hemminger q->clg.a4 = ge->k1; 778661b79725fea030803a89a16cda506bac8eeca78stephen hemminger break; 779661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } 780661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 781661b79725fea030803a89a16cda506bac8eeca78stephen hemminger default: 782661b79725fea030803a89a16cda506bac8eeca78stephen hemminger pr_info("netem: unknown loss type %u\n", type); 783661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return -EINVAL; 784661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } 785661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } 786661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 787661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return 0; 788661b79725fea030803a89a16cda506bac8eeca78stephen hemminger} 789661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 79027a3421e4821734bc19496faa77b380605dc3b23Patrick McHardystatic const struct nla_policy netem_policy[TCA_NETEM_MAX + 1] = { 79127a3421e4821734bc19496faa77b380605dc3b23Patrick McHardy [TCA_NETEM_CORR] = { .len = sizeof(struct tc_netem_corr) }, 79227a3421e4821734bc19496faa77b380605dc3b23Patrick McHardy [TCA_NETEM_REORDER] = { .len = sizeof(struct tc_netem_reorder) }, 79327a3421e4821734bc19496faa77b380605dc3b23Patrick McHardy [TCA_NETEM_CORRUPT] = { .len = sizeof(struct tc_netem_corrupt) }, 7947bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer [TCA_NETEM_RATE] = { .len = sizeof(struct tc_netem_rate) }, 795661b79725fea030803a89a16cda506bac8eeca78stephen hemminger [TCA_NETEM_LOSS] = { .type = NLA_NESTED }, 796e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet [TCA_NETEM_ECN] = { .type = NLA_U32 }, 7976a031f67c83aa175aedd10d4ae64750415ab57b0Yang Yingliang [TCA_NETEM_RATE64] = { .type = NLA_U64 }, 79827a3421e4821734bc19496faa77b380605dc3b23Patrick McHardy}; 79927a3421e4821734bc19496faa77b380605dc3b23Patrick McHardy 8002c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Grafstatic int parse_attr(struct nlattr *tb[], int maxtype, struct nlattr *nla, 8012c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf const struct nla_policy *policy, int len) 8022c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf{ 8032c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf int nested_len = nla_len(nla) - NLA_ALIGN(len); 8042c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf 805661b79725fea030803a89a16cda506bac8eeca78stephen hemminger if (nested_len < 0) { 806661b79725fea030803a89a16cda506bac8eeca78stephen hemminger pr_info("netem: invalid attributes len %d\n", nested_len); 8072c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf return -EINVAL; 808661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } 809661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 8102c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf if (nested_len >= nla_attr_size(0)) 8112c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf return nla_parse(tb, maxtype, nla_data(nla) + NLA_ALIGN(len), 8122c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf nested_len, policy); 813661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 8142c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1)); 8152c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf return 0; 8162c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf} 8172c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf 818c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger/* Parse netlink message to set options */ 8191e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardystatic int netem_change(struct Qdisc *sch, struct nlattr *opt) 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct netem_sched_data *q = qdisc_priv(sch); 822b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy struct nlattr *tb[TCA_NETEM_MAX + 1]; 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tc_netem_qopt *qopt; 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 82510297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki 826b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy if (opt == NULL) 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8292c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf qopt = nla_data(opt); 8302c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf ret = parse_attr(tb, TCA_NETEM_MAX, opt, netem_policy, sizeof(*qopt)); 831b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy if (ret < 0) 832b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy return ret; 833b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy 83450612537e9ab29693122fab20fc1eed235054ffeEric Dumazet sch->limit = qopt->limit; 83510297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q->latency = qopt->latency; 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q->jitter = qopt->jitter; 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q->limit = qopt->limit; 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q->gap = qopt->gap; 8400dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger q->counter = 0; 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q->loss = qopt->loss; 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q->duplicate = qopt->duplicate; 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 844bb2f8cc0ecf025d6d3947e0389434650023f432eStephen Hemminger /* for compatibility with earlier versions. 845bb2f8cc0ecf025d6d3947e0389434650023f432eStephen Hemminger * if gap is set, need to assume 100% probability 8460dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger */ 847a362e0a7890c735a3ef63aab12d71ecfc6e6f4a5Stephen Hemminger if (q->gap) 848a362e0a7890c735a3ef63aab12d71ecfc6e6f4a5Stephen Hemminger q->reorder = ~0; 8490dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger 850265eb67fb4e16be8e46a51e1e4e2ecd99fb15219Stephen Hemminger if (tb[TCA_NETEM_CORR]) 851265eb67fb4e16be8e46a51e1e4e2ecd99fb15219Stephen Hemminger get_correlation(sch, tb[TCA_NETEM_CORR]); 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 853b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy if (tb[TCA_NETEM_DELAY_DIST]) { 854b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy ret = get_dist_table(sch, tb[TCA_NETEM_DELAY_DIST]); 855b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy if (ret) 856b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy return ret; 857b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy } 858c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger 859265eb67fb4e16be8e46a51e1e4e2ecd99fb15219Stephen Hemminger if (tb[TCA_NETEM_REORDER]) 860265eb67fb4e16be8e46a51e1e4e2ecd99fb15219Stephen Hemminger get_reorder(sch, tb[TCA_NETEM_REORDER]); 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 862265eb67fb4e16be8e46a51e1e4e2ecd99fb15219Stephen Hemminger if (tb[TCA_NETEM_CORRUPT]) 863265eb67fb4e16be8e46a51e1e4e2ecd99fb15219Stephen Hemminger get_corrupt(sch, tb[TCA_NETEM_CORRUPT]); 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8657bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer if (tb[TCA_NETEM_RATE]) 8667bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer get_rate(sch, tb[TCA_NETEM_RATE]); 8677bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer 8686a031f67c83aa175aedd10d4ae64750415ab57b0Yang Yingliang if (tb[TCA_NETEM_RATE64]) 8696a031f67c83aa175aedd10d4ae64750415ab57b0Yang Yingliang q->rate = max_t(u64, q->rate, 8706a031f67c83aa175aedd10d4ae64750415ab57b0Yang Yingliang nla_get_u64(tb[TCA_NETEM_RATE64])); 8716a031f67c83aa175aedd10d4ae64750415ab57b0Yang Yingliang 872e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet if (tb[TCA_NETEM_ECN]) 873e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet q->ecn = nla_get_u32(tb[TCA_NETEM_ECN]); 874e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet 875661b79725fea030803a89a16cda506bac8eeca78stephen hemminger q->loss_model = CLG_RANDOM; 876661b79725fea030803a89a16cda506bac8eeca78stephen hemminger if (tb[TCA_NETEM_LOSS]) 877661b79725fea030803a89a16cda506bac8eeca78stephen hemminger ret = get_loss_clg(sch, tb[TCA_NETEM_LOSS]); 878661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 879661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return ret; 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8821e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardystatic int netem_init(struct Qdisc *sch, struct nlattr *opt) 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct netem_sched_data *q = qdisc_priv(sch); 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!opt) 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 89059cb5c6734021acc68590c7c2e0e92ad9a4952c6Patrick McHardy qdisc_watchdog_init(&q->watchdog, sch); 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 892661b79725fea030803a89a16cda506bac8eeca78stephen hemminger q->loss_model = CLG_RANDOM; 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = netem_change(sch, opt); 89450612537e9ab29693122fab20fc1eed235054ffeEric Dumazet if (ret) 895250a65f78265940ac33a2dd2002924e6126efe14stephen hemminger pr_info("netem: change failed\n"); 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void netem_destroy(struct Qdisc *sch) 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct netem_sched_data *q = qdisc_priv(sch); 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 90359cb5c6734021acc68590c7c2e0e92ad9a4952c6Patrick McHardy qdisc_watchdog_cancel(&q->watchdog); 90450612537e9ab29693122fab20fc1eed235054ffeEric Dumazet if (q->qdisc) 90550612537e9ab29693122fab20fc1eed235054ffeEric Dumazet qdisc_destroy(q->qdisc); 9066373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger dist_free(q->delay_dist); 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 909661b79725fea030803a89a16cda506bac8eeca78stephen hemmingerstatic int dump_loss_model(const struct netem_sched_data *q, 910661b79725fea030803a89a16cda506bac8eeca78stephen hemminger struct sk_buff *skb) 911661b79725fea030803a89a16cda506bac8eeca78stephen hemminger{ 912661b79725fea030803a89a16cda506bac8eeca78stephen hemminger struct nlattr *nest; 913661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 914661b79725fea030803a89a16cda506bac8eeca78stephen hemminger nest = nla_nest_start(skb, TCA_NETEM_LOSS); 915661b79725fea030803a89a16cda506bac8eeca78stephen hemminger if (nest == NULL) 916661b79725fea030803a89a16cda506bac8eeca78stephen hemminger goto nla_put_failure; 917661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 918661b79725fea030803a89a16cda506bac8eeca78stephen hemminger switch (q->loss_model) { 919661b79725fea030803a89a16cda506bac8eeca78stephen hemminger case CLG_RANDOM: 920661b79725fea030803a89a16cda506bac8eeca78stephen hemminger /* legacy loss model */ 921661b79725fea030803a89a16cda506bac8eeca78stephen hemminger nla_nest_cancel(skb, nest); 922661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return 0; /* no data */ 923661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 924661b79725fea030803a89a16cda506bac8eeca78stephen hemminger case CLG_4_STATES: { 925661b79725fea030803a89a16cda506bac8eeca78stephen hemminger struct tc_netem_gimodel gi = { 926661b79725fea030803a89a16cda506bac8eeca78stephen hemminger .p13 = q->clg.a1, 927661b79725fea030803a89a16cda506bac8eeca78stephen hemminger .p31 = q->clg.a2, 928661b79725fea030803a89a16cda506bac8eeca78stephen hemminger .p32 = q->clg.a3, 929661b79725fea030803a89a16cda506bac8eeca78stephen hemminger .p14 = q->clg.a4, 930661b79725fea030803a89a16cda506bac8eeca78stephen hemminger .p23 = q->clg.a5, 931661b79725fea030803a89a16cda506bac8eeca78stephen hemminger }; 932661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 9331b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller if (nla_put(skb, NETEM_LOSS_GI, sizeof(gi), &gi)) 9341b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller goto nla_put_failure; 935661b79725fea030803a89a16cda506bac8eeca78stephen hemminger break; 936661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } 937661b79725fea030803a89a16cda506bac8eeca78stephen hemminger case CLG_GILB_ELL: { 938661b79725fea030803a89a16cda506bac8eeca78stephen hemminger struct tc_netem_gemodel ge = { 939661b79725fea030803a89a16cda506bac8eeca78stephen hemminger .p = q->clg.a1, 940661b79725fea030803a89a16cda506bac8eeca78stephen hemminger .r = q->clg.a2, 941661b79725fea030803a89a16cda506bac8eeca78stephen hemminger .h = q->clg.a3, 942661b79725fea030803a89a16cda506bac8eeca78stephen hemminger .k1 = q->clg.a4, 943661b79725fea030803a89a16cda506bac8eeca78stephen hemminger }; 944661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 9451b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller if (nla_put(skb, NETEM_LOSS_GE, sizeof(ge), &ge)) 9461b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller goto nla_put_failure; 947661b79725fea030803a89a16cda506bac8eeca78stephen hemminger break; 948661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } 949661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } 950661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 951661b79725fea030803a89a16cda506bac8eeca78stephen hemminger nla_nest_end(skb, nest); 952661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return 0; 953661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 954661b79725fea030803a89a16cda506bac8eeca78stephen hemmingernla_put_failure: 955661b79725fea030803a89a16cda506bac8eeca78stephen hemminger nla_nest_cancel(skb, nest); 956661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return -1; 957661b79725fea030803a89a16cda506bac8eeca78stephen hemminger} 958661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int netem_dump(struct Qdisc *sch, struct sk_buff *skb) 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct netem_sched_data *q = qdisc_priv(sch); 962861d7f745f37506bbd90227e97b95baf2a5fac34stephen hemminger struct nlattr *nla = (struct nlattr *) skb_tail_pointer(skb); 9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tc_netem_qopt qopt; 9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tc_netem_corr cor; 9650dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger struct tc_netem_reorder reorder; 966c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger struct tc_netem_corrupt corrupt; 9677bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer struct tc_netem_rate rate; 9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qopt.latency = q->latency; 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qopt.jitter = q->jitter; 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qopt.limit = q->limit; 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qopt.loss = q->loss; 9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qopt.gap = q->gap; 9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qopt.duplicate = q->duplicate; 9751b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller if (nla_put(skb, TCA_OPTIONS, sizeof(qopt), &qopt)) 9761b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller goto nla_put_failure; 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cor.delay_corr = q->delay_cor.rho; 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cor.loss_corr = q->loss_cor.rho; 9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cor.dup_corr = q->dup_cor.rho; 9811b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller if (nla_put(skb, TCA_NETEM_CORR, sizeof(cor), &cor)) 9821b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller goto nla_put_failure; 9830dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger 9840dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger reorder.probability = q->reorder; 9850dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger reorder.correlation = q->reorder_cor.rho; 9861b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller if (nla_put(skb, TCA_NETEM_REORDER, sizeof(reorder), &reorder)) 9871b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller goto nla_put_failure; 9880dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger 989c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger corrupt.probability = q->corrupt; 990c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger corrupt.correlation = q->corrupt_cor.rho; 9911b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller if (nla_put(skb, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt)) 9921b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller goto nla_put_failure; 993c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger 9946a031f67c83aa175aedd10d4ae64750415ab57b0Yang Yingliang if (q->rate >= (1ULL << 32)) { 9956a031f67c83aa175aedd10d4ae64750415ab57b0Yang Yingliang if (nla_put_u64(skb, TCA_NETEM_RATE64, q->rate)) 9966a031f67c83aa175aedd10d4ae64750415ab57b0Yang Yingliang goto nla_put_failure; 9976a031f67c83aa175aedd10d4ae64750415ab57b0Yang Yingliang rate.rate = ~0U; 9986a031f67c83aa175aedd10d4ae64750415ab57b0Yang Yingliang } else { 9996a031f67c83aa175aedd10d4ae64750415ab57b0Yang Yingliang rate.rate = q->rate; 10006a031f67c83aa175aedd10d4ae64750415ab57b0Yang Yingliang } 100190b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer rate.packet_overhead = q->packet_overhead; 100290b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer rate.cell_size = q->cell_size; 100390b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer rate.cell_overhead = q->cell_overhead; 10041b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller if (nla_put(skb, TCA_NETEM_RATE, sizeof(rate), &rate)) 10051b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller goto nla_put_failure; 10067bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer 1007e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet if (q->ecn && nla_put_u32(skb, TCA_NETEM_ECN, q->ecn)) 1008e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet goto nla_put_failure; 1009e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet 1010661b79725fea030803a89a16cda506bac8eeca78stephen hemminger if (dump_loss_model(q, skb) != 0) 1011661b79725fea030803a89a16cda506bac8eeca78stephen hemminger goto nla_put_failure; 1012661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 1013861d7f745f37506bbd90227e97b95baf2a5fac34stephen hemminger return nla_nest_end(skb, nla); 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10151e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardynla_put_failure: 1016861d7f745f37506bbd90227e97b95baf2a5fac34stephen hemminger nlmsg_trim(skb, nla); 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 102010f6dfcfde884441db89dc66b945d6c948e1d356stephen hemmingerstatic int netem_dump_class(struct Qdisc *sch, unsigned long cl, 102110f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger struct sk_buff *skb, struct tcmsg *tcm) 102210f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger{ 102310f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger struct netem_sched_data *q = qdisc_priv(sch); 102410f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger 102550612537e9ab29693122fab20fc1eed235054ffeEric Dumazet if (cl != 1 || !q->qdisc) /* only one class */ 102610f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger return -ENOENT; 102710f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger 102810f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger tcm->tcm_handle |= TC_H_MIN(1); 102910f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger tcm->tcm_info = q->qdisc->handle; 103010f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger 103110f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger return 0; 103210f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger} 103310f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger 103410f6dfcfde884441db89dc66b945d6c948e1d356stephen hemmingerstatic int netem_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, 103510f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger struct Qdisc **old) 103610f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger{ 103710f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger struct netem_sched_data *q = qdisc_priv(sch); 103810f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger 103910f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger sch_tree_lock(sch); 104010f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger *old = q->qdisc; 104110f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger q->qdisc = new; 104250612537e9ab29693122fab20fc1eed235054ffeEric Dumazet if (*old) { 104350612537e9ab29693122fab20fc1eed235054ffeEric Dumazet qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); 104450612537e9ab29693122fab20fc1eed235054ffeEric Dumazet qdisc_reset(*old); 104550612537e9ab29693122fab20fc1eed235054ffeEric Dumazet } 104610f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger sch_tree_unlock(sch); 104710f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger 104810f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger return 0; 104910f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger} 105010f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger 105110f6dfcfde884441db89dc66b945d6c948e1d356stephen hemmingerstatic struct Qdisc *netem_leaf(struct Qdisc *sch, unsigned long arg) 105210f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger{ 105310f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger struct netem_sched_data *q = qdisc_priv(sch); 105410f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger return q->qdisc; 105510f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger} 105610f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger 105710f6dfcfde884441db89dc66b945d6c948e1d356stephen hemmingerstatic unsigned long netem_get(struct Qdisc *sch, u32 classid) 105810f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger{ 105910f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger return 1; 106010f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger} 106110f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger 106210f6dfcfde884441db89dc66b945d6c948e1d356stephen hemmingerstatic void netem_put(struct Qdisc *sch, unsigned long arg) 106310f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger{ 106410f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger} 106510f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger 106610f6dfcfde884441db89dc66b945d6c948e1d356stephen hemmingerstatic void netem_walk(struct Qdisc *sch, struct qdisc_walker *walker) 106710f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger{ 106810f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger if (!walker->stop) { 106910f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger if (walker->count >= walker->skip) 107010f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger if (walker->fn(sch, 1, walker) < 0) { 107110f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger walker->stop = 1; 107210f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger return; 107310f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger } 107410f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger walker->count++; 107510f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger } 107610f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger} 107710f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger 107810f6dfcfde884441db89dc66b945d6c948e1d356stephen hemmingerstatic const struct Qdisc_class_ops netem_class_ops = { 107910f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger .graft = netem_graft, 108010f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger .leaf = netem_leaf, 108110f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger .get = netem_get, 108210f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger .put = netem_put, 108310f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger .walk = netem_walk, 108410f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger .dump = netem_dump_class, 108510f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger}; 108610f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger 108720fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazetstatic struct Qdisc_ops netem_qdisc_ops __read_mostly = { 10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id = "netem", 108910f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger .cl_ops = &netem_class_ops, 10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .priv_size = sizeof(struct netem_sched_data), 10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .enqueue = netem_enqueue, 10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .dequeue = netem_dequeue, 109377be155cba4e163e8bba9fd27222a8b6189ec4f7Jarek Poplawski .peek = qdisc_peek_dequeued, 10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .drop = netem_drop, 10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .init = netem_init, 10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .reset = netem_reset, 10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .destroy = netem_destroy, 10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .change = netem_change, 10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .dump = netem_dump, 11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init netem_module_init(void) 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1106eb229c4cdc3389682cda20adb015ba767950a220Stephen Hemminger pr_info("netem: version " VERSION "\n"); 11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return register_qdisc(&netem_qdisc_ops); 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit netem_module_exit(void) 11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_qdisc(&netem_qdisc_ops); 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(netem_module_init) 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(netem_module_exit) 11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 1116