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 120c045a734da4cb6d4665962f252de3d8871136ae9Yang Yingliang enum { 121c045a734da4cb6d4665962f252de3d8871136ae9Yang Yingliang GOOD_STATE = 1, 122c045a734da4cb6d4665962f252de3d8871136ae9Yang Yingliang BAD_STATE, 123c045a734da4cb6d4665962f252de3d8871136ae9Yang Yingliang } GE_state_model; 124c045a734da4cb6d4665962f252de3d8871136ae9Yang Yingliang 125661b79725fea030803a89a16cda506bac8eeca78stephen hemminger /* Correlated Loss Generation models */ 126661b79725fea030803a89a16cda506bac8eeca78stephen hemminger struct clgstate { 127661b79725fea030803a89a16cda506bac8eeca78stephen hemminger /* state of the Markov chain */ 128661b79725fea030803a89a16cda506bac8eeca78stephen hemminger u8 state; 129661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 130661b79725fea030803a89a16cda506bac8eeca78stephen hemminger /* 4-states and Gilbert-Elliot models */ 131661b79725fea030803a89a16cda506bac8eeca78stephen hemminger u32 a1; /* p13 for 4-states or p for GE */ 132661b79725fea030803a89a16cda506bac8eeca78stephen hemminger u32 a2; /* p31 for 4-states or r for GE */ 133661b79725fea030803a89a16cda506bac8eeca78stephen hemminger u32 a3; /* p32 for 4-states or h for GE */ 134661b79725fea030803a89a16cda506bac8eeca78stephen hemminger u32 a4; /* p14 for 4-states or 1-k for GE */ 135661b79725fea030803a89a16cda506bac8eeca78stephen hemminger u32 a5; /* p23 used only in 4-states */ 136661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } clg; 137661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14050612537e9ab29693122fab20fc1eed235054ffeEric Dumazet/* Time stamp put into socket buffer control block 14150612537e9ab29693122fab20fc1eed235054ffeEric Dumazet * Only valid when skbs are in our internal t(ime)fifo queue. 14250612537e9ab29693122fab20fc1eed235054ffeEric Dumazet */ 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct netem_skb_cb { 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds psched_time_t time_to_send; 145aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet ktime_t tstamp_save; 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 148aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet/* Because space in skb->cb[] is tight, netem overloads skb->next/prev/tstamp 149aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet * to hold a rb_node structure. 150aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet * 151aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet * If struct sk_buff layout is changed, the following checks will complain. 152aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet */ 153aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazetstatic struct rb_node *netem_rb_node(struct sk_buff *skb) 154aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet{ 155aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet BUILD_BUG_ON(offsetof(struct sk_buff, next) != 0); 156aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet BUILD_BUG_ON(offsetof(struct sk_buff, prev) != 157aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet offsetof(struct sk_buff, next) + sizeof(skb->next)); 158aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet BUILD_BUG_ON(offsetof(struct sk_buff, tstamp) != 159aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet offsetof(struct sk_buff, prev) + sizeof(skb->prev)); 160aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet BUILD_BUG_ON(sizeof(struct rb_node) > sizeof(skb->next) + 161aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet sizeof(skb->prev) + 162aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet sizeof(skb->tstamp)); 163aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet return (struct rb_node *)&skb->next; 164aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet} 165aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet 166aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazetstatic struct sk_buff *netem_rb_to_skb(struct rb_node *rb) 167aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet{ 168aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet return (struct sk_buff *)rb; 169aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet} 170aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet 1715f86173bdf15981ca49d0434f638b68f70a35644Jussi Kivilinnastatic inline struct netem_skb_cb *netem_skb_cb(struct sk_buff *skb) 1725f86173bdf15981ca49d0434f638b68f70a35644Jussi Kivilinna{ 173aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet /* we assume we can use skb next/prev/tstamp as storage for rb_node */ 17416bda13d90c8d5da243e2cfa1677e62ecce26860David S. Miller qdisc_cb_private_validate(skb, sizeof(struct netem_skb_cb)); 175175f9c1bba9b825d22b142d183c9e175488b260cJussi Kivilinna return (struct netem_skb_cb *)qdisc_skb_cb(skb)->data; 1765f86173bdf15981ca49d0434f638b68f70a35644Jussi Kivilinna} 1775f86173bdf15981ca49d0434f638b68f70a35644Jussi Kivilinna 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* init_crandom - initialize correlated random number generator 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Use entropy source for initial seed. 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void init_crandom(struct crndstate *state, unsigned long rho) 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds state->rho = rho; 18463862b5bef7349dd1137e4c70702c67d77565785Aruna-Hewapathirane state->last = prandom_u32(); 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* get_crandom - correlated random number generator 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Next number depends on last value. 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * rho is scaled to avoid floating point. 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 191b407621c35ed5f9a0734e57472e9539117963768Stephen Hemmingerstatic u32 get_crandom(struct crndstate *state) 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u64 value, rho; 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long answer; 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 196bb2f8cc0ecf025d6d3947e0389434650023f432eStephen Hemminger if (state->rho == 0) /* no correlation */ 19763862b5bef7349dd1137e4c70702c67d77565785Aruna-Hewapathirane return prandom_u32(); 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19963862b5bef7349dd1137e4c70702c67d77565785Aruna-Hewapathirane value = prandom_u32(); 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rho = (u64)state->rho + 1; 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds answer = (value * ((1ull<<32) - rho) + state->last * rho) >> 32; 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds state->last = answer; 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return answer; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 206661b79725fea030803a89a16cda506bac8eeca78stephen hemminger/* loss_4state - 4-state model loss generator 207661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * Generates losses according to the 4-state Markov chain adopted in 208661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * the GI (General and Intuitive) loss model. 209661b79725fea030803a89a16cda506bac8eeca78stephen hemminger */ 210661b79725fea030803a89a16cda506bac8eeca78stephen hemmingerstatic bool loss_4state(struct netem_sched_data *q) 211661b79725fea030803a89a16cda506bac8eeca78stephen hemminger{ 212661b79725fea030803a89a16cda506bac8eeca78stephen hemminger struct clgstate *clg = &q->clg; 21363862b5bef7349dd1137e4c70702c67d77565785Aruna-Hewapathirane u32 rnd = prandom_u32(); 214661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 215661b79725fea030803a89a16cda506bac8eeca78stephen hemminger /* 21625985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * Makes a comparison between rnd and the transition 217661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * probabilities outgoing from the current state, then decides the 218661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * next state and if the next packet has to be transmitted or lost. 219661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * The four states correspond to: 220a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang * TX_IN_GAP_PERIOD => successfully transmitted packets within a gap period 221a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang * LOST_IN_BURST_PERIOD => isolated losses within a gap period 222a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang * LOST_IN_GAP_PERIOD => lost packets within a burst period 223a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang * TX_IN_GAP_PERIOD => successfully transmitted packets within a burst period 224661b79725fea030803a89a16cda506bac8eeca78stephen hemminger */ 225661b79725fea030803a89a16cda506bac8eeca78stephen hemminger switch (clg->state) { 226a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang case TX_IN_GAP_PERIOD: 227661b79725fea030803a89a16cda506bac8eeca78stephen hemminger if (rnd < clg->a4) { 228a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang clg->state = LOST_IN_BURST_PERIOD; 229661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return true; 230ab6c27be8178a4682446faa5aa017b948997937fstephen hemminger } else if (clg->a4 < rnd && rnd < clg->a1 + clg->a4) { 231a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang clg->state = LOST_IN_GAP_PERIOD; 232661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return true; 233a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang } else if (clg->a1 + clg->a4 < rnd) { 234a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang clg->state = TX_IN_GAP_PERIOD; 235a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang } 236661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 237661b79725fea030803a89a16cda506bac8eeca78stephen hemminger break; 238a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang case TX_IN_BURST_PERIOD: 239661b79725fea030803a89a16cda506bac8eeca78stephen hemminger if (rnd < clg->a5) { 240a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang clg->state = LOST_IN_GAP_PERIOD; 241661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return true; 242a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang } else { 243a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang clg->state = TX_IN_BURST_PERIOD; 244a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang } 245661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 246661b79725fea030803a89a16cda506bac8eeca78stephen hemminger break; 247a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang case LOST_IN_GAP_PERIOD: 248661b79725fea030803a89a16cda506bac8eeca78stephen hemminger if (rnd < clg->a3) 249a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang clg->state = TX_IN_BURST_PERIOD; 250661b79725fea030803a89a16cda506bac8eeca78stephen hemminger else if (clg->a3 < rnd && rnd < clg->a2 + clg->a3) { 251a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang clg->state = TX_IN_GAP_PERIOD; 252661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } else if (clg->a2 + clg->a3 < rnd) { 253a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang clg->state = LOST_IN_GAP_PERIOD; 254661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return true; 255661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } 256661b79725fea030803a89a16cda506bac8eeca78stephen hemminger break; 257a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang case LOST_IN_BURST_PERIOD: 258a6e2fe17eba47681e82cdb9cfed5a67b57802a78Yang Yingliang clg->state = TX_IN_GAP_PERIOD; 259661b79725fea030803a89a16cda506bac8eeca78stephen hemminger break; 260661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } 261661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 262661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return false; 263661b79725fea030803a89a16cda506bac8eeca78stephen hemminger} 264661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 265661b79725fea030803a89a16cda506bac8eeca78stephen hemminger/* loss_gilb_ell - Gilbert-Elliot model loss generator 266661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * Generates losses according to the Gilbert-Elliot loss model or 267661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * its special cases (Gilbert or Simple Gilbert) 268661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * 26925985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * Makes a comparison between random number and the transition 270661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * probabilities outgoing from the current state, then decides the 27125985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * next state. A second random number is extracted and the comparison 272661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * with the loss probability of the current state decides if the next 273661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * packet will be transmitted or lost. 274661b79725fea030803a89a16cda506bac8eeca78stephen hemminger */ 275661b79725fea030803a89a16cda506bac8eeca78stephen hemmingerstatic bool loss_gilb_ell(struct netem_sched_data *q) 276661b79725fea030803a89a16cda506bac8eeca78stephen hemminger{ 277661b79725fea030803a89a16cda506bac8eeca78stephen hemminger struct clgstate *clg = &q->clg; 278661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 279661b79725fea030803a89a16cda506bac8eeca78stephen hemminger switch (clg->state) { 280c045a734da4cb6d4665962f252de3d8871136ae9Yang Yingliang case GOOD_STATE: 28163862b5bef7349dd1137e4c70702c67d77565785Aruna-Hewapathirane if (prandom_u32() < clg->a1) 282c045a734da4cb6d4665962f252de3d8871136ae9Yang Yingliang clg->state = BAD_STATE; 28363862b5bef7349dd1137e4c70702c67d77565785Aruna-Hewapathirane if (prandom_u32() < clg->a4) 284661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return true; 2857c2781fa92f5b9ca3188817a56a2ced0400355f3stephen hemminger break; 286c045a734da4cb6d4665962f252de3d8871136ae9Yang Yingliang case BAD_STATE: 28763862b5bef7349dd1137e4c70702c67d77565785Aruna-Hewapathirane if (prandom_u32() < clg->a2) 288c045a734da4cb6d4665962f252de3d8871136ae9Yang Yingliang clg->state = GOOD_STATE; 28963862b5bef7349dd1137e4c70702c67d77565785Aruna-Hewapathirane if (prandom_u32() > clg->a3) 290661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return true; 291661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } 292661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 293661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return false; 294661b79725fea030803a89a16cda506bac8eeca78stephen hemminger} 295661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 296661b79725fea030803a89a16cda506bac8eeca78stephen hemmingerstatic bool loss_event(struct netem_sched_data *q) 297661b79725fea030803a89a16cda506bac8eeca78stephen hemminger{ 298661b79725fea030803a89a16cda506bac8eeca78stephen hemminger switch (q->loss_model) { 299661b79725fea030803a89a16cda506bac8eeca78stephen hemminger case CLG_RANDOM: 300661b79725fea030803a89a16cda506bac8eeca78stephen hemminger /* Random packet drop 0 => none, ~0 => all */ 301661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return q->loss && q->loss >= get_crandom(&q->loss_cor); 302661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 303661b79725fea030803a89a16cda506bac8eeca78stephen hemminger case CLG_4_STATES: 304661b79725fea030803a89a16cda506bac8eeca78stephen hemminger /* 4state loss model algorithm (used also for GI model) 305661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * Extracts a value from the markov 4 state loss generator, 306661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * if it is 1 drops a packet and if needed writes the event in 307661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * the kernel logs 308661b79725fea030803a89a16cda506bac8eeca78stephen hemminger */ 309661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return loss_4state(q); 310661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 311661b79725fea030803a89a16cda506bac8eeca78stephen hemminger case CLG_GILB_ELL: 312661b79725fea030803a89a16cda506bac8eeca78stephen hemminger /* Gilbert-Elliot loss model algorithm 313661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * Extracts a value from the Gilbert-Elliot loss generator, 314661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * if it is 1 drops a packet and if needed writes the event in 315661b79725fea030803a89a16cda506bac8eeca78stephen hemminger * the kernel logs 316661b79725fea030803a89a16cda506bac8eeca78stephen hemminger */ 317661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return loss_gilb_ell(q); 318661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } 319661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 320661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return false; /* not reached */ 321661b79725fea030803a89a16cda506bac8eeca78stephen hemminger} 322661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 323661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* tabledist - return a pseudo-randomly distributed value with mean mu and 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * std deviation sigma. Uses table lookup to approximate the desired 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * distribution, and a uniformly-distributed pseudo-random source. 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 328b407621c35ed5f9a0734e57472e9539117963768Stephen Hemmingerstatic psched_tdiff_t tabledist(psched_tdiff_t mu, psched_tdiff_t sigma, 329b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger struct crndstate *state, 330b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger const struct disttable *dist) 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 332b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger psched_tdiff_t x; 333b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger long t; 334b407621c35ed5f9a0734e57472e9539117963768Stephen Hemminger u32 rnd; 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sigma == 0) 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return mu; 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rnd = get_crandom(state); 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* default uniform distribution */ 34210297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki if (dist == NULL) 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (rnd % (2*sigma)) - sigma + mu; 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds t = dist->table[rnd % dist->size]; 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds x = (sigma % NETEM_DIST_SCALE) * t; 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (x >= 0) 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds x += NETEM_DIST_SCALE/2; 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds x -= NETEM_DIST_SCALE/2; 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return x / NETEM_DIST_SCALE + (sigma / NETEM_DIST_SCALE) * t + mu; 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35590b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeiferstatic psched_time_t packet_len_2_sched_time(unsigned int len, struct netem_sched_data *q) 3567bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer{ 35790b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer u64 ticks; 358fc33cc72423ed3474cd51bc8bd7c1cdc22a78e1aEric Dumazet 35990b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer len += q->packet_overhead; 36090b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer 36190b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer if (q->cell_size) { 36290b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer u32 cells = reciprocal_divide(len, q->cell_size_reciprocal); 36390b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer 36490b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer if (len > cells * q->cell_size) /* extra cell needed for remainder */ 36590b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer cells++; 36690b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer len = cells * (q->cell_size + q->cell_overhead); 36790b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer } 36890b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer 36990b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer ticks = (u64)len * NSEC_PER_SEC; 37090b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer 37190b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer do_div(ticks, q->rate); 372fc33cc72423ed3474cd51bc8bd7c1cdc22a78e1aEric Dumazet return PSCHED_NS2TICKS(ticks); 3737bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer} 3747bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer 375ff704050f2fc0f3382b5a70bba56a51a3feca79dstephen hemmingerstatic void tfifo_reset(struct Qdisc *sch) 376ff704050f2fc0f3382b5a70bba56a51a3feca79dstephen hemminger{ 377ff704050f2fc0f3382b5a70bba56a51a3feca79dstephen hemminger struct netem_sched_data *q = qdisc_priv(sch); 378ff704050f2fc0f3382b5a70bba56a51a3feca79dstephen hemminger struct rb_node *p; 379ff704050f2fc0f3382b5a70bba56a51a3feca79dstephen hemminger 380ff704050f2fc0f3382b5a70bba56a51a3feca79dstephen hemminger while ((p = rb_first(&q->t_root))) { 381ff704050f2fc0f3382b5a70bba56a51a3feca79dstephen hemminger struct sk_buff *skb = netem_rb_to_skb(p); 382ff704050f2fc0f3382b5a70bba56a51a3feca79dstephen hemminger 383ff704050f2fc0f3382b5a70bba56a51a3feca79dstephen hemminger rb_erase(p, &q->t_root); 384ff704050f2fc0f3382b5a70bba56a51a3feca79dstephen hemminger skb->next = NULL; 385ff704050f2fc0f3382b5a70bba56a51a3feca79dstephen hemminger skb->prev = NULL; 386ff704050f2fc0f3382b5a70bba56a51a3feca79dstephen hemminger kfree_skb(skb); 387ff704050f2fc0f3382b5a70bba56a51a3feca79dstephen hemminger } 388ff704050f2fc0f3382b5a70bba56a51a3feca79dstephen hemminger} 389ff704050f2fc0f3382b5a70bba56a51a3feca79dstephen hemminger 390960fb66e520a405dde39ff883f17ff2669c13d85Eric Dumazetstatic void tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch) 39150612537e9ab29693122fab20fc1eed235054ffeEric Dumazet{ 392aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet struct netem_sched_data *q = qdisc_priv(sch); 39350612537e9ab29693122fab20fc1eed235054ffeEric Dumazet psched_time_t tnext = netem_skb_cb(nskb)->time_to_send; 394aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet struct rb_node **p = &q->t_root.rb_node, *parent = NULL; 39550612537e9ab29693122fab20fc1eed235054ffeEric Dumazet 396aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet while (*p) { 397aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet struct sk_buff *skb; 39850612537e9ab29693122fab20fc1eed235054ffeEric Dumazet 399aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet parent = *p; 400aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet skb = netem_rb_to_skb(parent); 401960fb66e520a405dde39ff883f17ff2669c13d85Eric Dumazet if (tnext >= netem_skb_cb(skb)->time_to_send) 402aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet p = &parent->rb_right; 403aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet else 404aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet p = &parent->rb_left; 40550612537e9ab29693122fab20fc1eed235054ffeEric Dumazet } 406aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet rb_link_node(netem_rb_node(nskb), parent, p); 407aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet rb_insert_color(netem_rb_node(nskb), &q->t_root); 408aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet sch->q.qlen++; 40950612537e9ab29693122fab20fc1eed235054ffeEric Dumazet} 41050612537e9ab29693122fab20fc1eed235054ffeEric Dumazet 4110afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger/* 4120afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger * Insert one skb into qdisc. 4130afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger * Note: parent depends on return value to account for queue length. 4140afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger * NET_XMIT_DROP: queue length didn't change. 4150afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger * NET_XMIT_SUCCESS: one skb was queued. 4160afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger */ 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct netem_sched_data *q = qdisc_priv(sch); 42089e1df74f841fc31e81838d30594c4eff01859f8Guillaume Chazarain /* We don't fill cb now as skb_unshare() may invalidate it */ 42189e1df74f841fc31e81838d30594c4eff01859f8Guillaume Chazarain struct netem_skb_cb *cb; 4220afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger struct sk_buff *skb2; 4230afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger int count = 1; 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4250afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger /* Random duplication */ 4260afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger if (q->duplicate && q->duplicate >= get_crandom(&q->dup_cor)) 4270afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger ++count; 4280afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger 429661b79725fea030803a89a16cda506bac8eeca78stephen hemminger /* Drop packet? */ 430e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet if (loss_event(q)) { 431e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet if (q->ecn && INET_ECN_set_ce(skb)) 43225331d6ce42bcf4b34b6705fce4da15c3fabe62fJohn Fastabend qdisc_qstats_drop(sch); /* mark packet */ 433e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet else 434e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet --count; 435e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet } 4360afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger if (count == 0) { 43725331d6ce42bcf4b34b6705fce4da15c3fabe62fJohn Fastabend qdisc_qstats_drop(sch); 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree_skb(skb); 439c27f339af90bb874a7a9c680b17abfd32d4a727bJarek Poplawski return NET_XMIT_SUCCESS | __NET_XMIT_BYPASS; 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4425a308f40bfe27fcfd1db3970afe18b635f23c182Eric Dumazet /* If a delay is expected, orphan the skb. (orphaning usually takes 4435a308f40bfe27fcfd1db3970afe18b635f23c182Eric Dumazet * place at TX completion time, so _before_ the link transit delay) 4445a308f40bfe27fcfd1db3970afe18b635f23c182Eric Dumazet */ 4455a308f40bfe27fcfd1db3970afe18b635f23c182Eric Dumazet if (q->latency || q->jitter) 446f2f872f9272a79a1048877ea14c15576f46c225eEric Dumazet skb_orphan_partial(skb); 4474e8a5201506423e0241202de1349422af4260296David S. Miller 4480afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger /* 4490afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger * If we need to duplicate packet, then re-insert at top of the 4500afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger * qdisc tree, since parent queuer expects that only one 4510afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger * skb will be queued. 4520afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger */ 4530afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger if (count > 1 && (skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) { 4547698b4fcabcd790efc4f226bada1e7b5870653afDavid S. Miller struct Qdisc *rootq = qdisc_root(sch); 4550afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger u32 dupsave = q->duplicate; /* prevent duplicating a dup... */ 4560afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger q->duplicate = 0; 4570afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger 4585f86173bdf15981ca49d0434f638b68f70a35644Jussi Kivilinna qdisc_enqueue_root(skb2, rootq); 4590afb51e72855971dba83b3c6b70c547c2d1161fdStephen Hemminger q->duplicate = dupsave; 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 462c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger /* 463c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger * Randomized packet corruption. 464c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger * Make copy if needed since we are modifying 465c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger * If packet is going to be hardware checksummed, then 466c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger * do it now in software before we mangle it. 467c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger */ 468c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger if (q->corrupt && q->corrupt >= get_crandom(&q->corrupt_cor)) { 469f64f9e719261a87818dd192a3a2352e5b20fbd0fJoe Perches if (!(skb = skb_unshare(skb, GFP_ATOMIC)) || 470f64f9e719261a87818dd192a3a2352e5b20fbd0fJoe Perches (skb->ip_summed == CHECKSUM_PARTIAL && 471116a0fc31c6c9b8fc821be5a96e5bf0b43260131Eric Dumazet skb_checksum_help(skb))) 472116a0fc31c6c9b8fc821be5a96e5bf0b43260131Eric Dumazet return qdisc_drop(skb, sch); 473c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger 47463862b5bef7349dd1137e4c70702c67d77565785Aruna-Hewapathirane skb->data[prandom_u32() % skb_headlen(skb)] ^= 47563862b5bef7349dd1137e4c70702c67d77565785Aruna-Hewapathirane 1<<(prandom_u32() % 8); 476c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger } 477c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger 478960fb66e520a405dde39ff883f17ff2669c13d85Eric Dumazet if (unlikely(skb_queue_len(&sch->q) >= sch->limit)) 479960fb66e520a405dde39ff883f17ff2669c13d85Eric Dumazet return qdisc_reshape_fail(skb, sch); 480960fb66e520a405dde39ff883f17ff2669c13d85Eric Dumazet 48125331d6ce42bcf4b34b6705fce4da15c3fabe62fJohn Fastabend qdisc_qstats_backlog_inc(sch, skb); 482960fb66e520a405dde39ff883f17ff2669c13d85Eric Dumazet 4835f86173bdf15981ca49d0434f638b68f70a35644Jussi Kivilinna cb = netem_skb_cb(skb); 484cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazet if (q->gap == 0 || /* not doing reordering */ 485a42b4799c683723e8c464de4026af085b2ebd5faVijay Subramanian q->counter < q->gap - 1 || /* inside last reordering gap */ 486f64f9e719261a87818dd192a3a2352e5b20fbd0fJoe Perches q->reorder < get_crandom(&q->reorder_cor)) { 4870f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger psched_time_t now; 48807aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger psched_tdiff_t delay; 48907aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger 49007aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger delay = tabledist(q->latency, q->jitter, 49107aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger &q->delay_cor, q->delay_dist); 49207aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger 4933bebcda28077375470dd60545b71bba2f83335fdPatrick McHardy now = psched_get_time(); 4947bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer 4957bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer if (q->rate) { 496aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet struct sk_buff *last; 4977bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer 498aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet if (!skb_queue_empty(&sch->q)) 499aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet last = skb_peek_tail(&sch->q); 500aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet else 501aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet last = netem_rb_to_skb(rb_last(&q->t_root)); 502aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet if (last) { 5037bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer /* 504a13d3104710184ecc43edc35a25ae8092058463fJohannes Naab * Last packet in queue is reference point (now), 505a13d3104710184ecc43edc35a25ae8092058463fJohannes Naab * calculate this time bonus and subtract 5067bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer * from delay. 5077bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer */ 508aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet delay -= netem_skb_cb(last)->time_to_send - now; 509a13d3104710184ecc43edc35a25ae8092058463fJohannes Naab delay = max_t(psched_tdiff_t, 0, delay); 510aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet now = netem_skb_cb(last)->time_to_send; 5117bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer } 512a13d3104710184ecc43edc35a25ae8092058463fJohannes Naab 5138cfd88d6d70735c47b17aef855b4c81dde83c85cYang Yingliang delay += packet_len_2_sched_time(qdisc_pkt_len(skb), q); 5147bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer } 5157bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer 5167c59e25f3186f26e85b13a318dbc4482d1d363e9Patrick McHardy cb->time_to_send = now + delay; 517aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet cb->tstamp_save = skb->tstamp; 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++q->counter; 519960fb66e520a405dde39ff883f17ff2669c13d85Eric Dumazet tfifo_enqueue(skb, sch); 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 52110297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki /* 5220dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger * Do re-ordering by putting one out of N packets at the front 5230dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger * of the queue. 5240dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger */ 5253bebcda28077375470dd60545b71bba2f83335fdPatrick McHardy cb->time_to_send = psched_get_time(); 5260dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger q->counter = 0; 5278ba25dad0ac78850cd46d91186a27d60f7314752Jarek Poplawski 52850612537e9ab29693122fab20fc1eed235054ffeEric Dumazet __skb_queue_head(&sch->q, skb); 529eb10192447370f19a215a8c2749332afa1199d46Hagen Paul Pfeifer sch->qstats.requeues++; 530378a2f090f7a478704a372a4869b8a9ac206234eJarek Poplawski } 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 53210f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger return NET_XMIT_SUCCESS; 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 535cc7ec456f82da7f89a5b376e613b3ac4311b3e9aEric Dumazetstatic unsigned int netem_drop(struct Qdisc *sch) 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct netem_sched_data *q = qdisc_priv(sch); 53850612537e9ab29693122fab20fc1eed235054ffeEric Dumazet unsigned int len; 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 54050612537e9ab29693122fab20fc1eed235054ffeEric Dumazet len = qdisc_queue_drop(sch); 541aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet 542aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet if (!len) { 543aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet struct rb_node *p = rb_first(&q->t_root); 544aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet 545aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet if (p) { 546aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet struct sk_buff *skb = netem_rb_to_skb(p); 547aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet 548aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet rb_erase(p, &q->t_root); 549aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet sch->q.qlen--; 550aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet skb->next = NULL; 551aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet skb->prev = NULL; 55225331d6ce42bcf4b34b6705fce4da15c3fabe62fJohn Fastabend qdisc_qstats_backlog_dec(sch, skb); 553aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet kfree_skb(skb); 554aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet } 555aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet } 55650612537e9ab29693122fab20fc1eed235054ffeEric Dumazet if (!len && q->qdisc && q->qdisc->ops->drop) 55750612537e9ab29693122fab20fc1eed235054ffeEric Dumazet len = q->qdisc->ops->drop(q->qdisc); 55850612537e9ab29693122fab20fc1eed235054ffeEric Dumazet if (len) 55925331d6ce42bcf4b34b6705fce4da15c3fabe62fJohn Fastabend qdisc_qstats_drop(sch); 56050612537e9ab29693122fab20fc1eed235054ffeEric Dumazet 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return len; 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sk_buff *netem_dequeue(struct Qdisc *sch) 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct netem_sched_data *q = qdisc_priv(sch); 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 568aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet struct rb_node *p; 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 570fd245a4adb5288eac37250875f237c40a20a1944Eric Dumazet if (qdisc_is_throttled(sch)) 57111274e5a43266d531140530adebead6903380cafStephen Hemminger return NULL; 57211274e5a43266d531140530adebead6903380cafStephen Hemminger 57350612537e9ab29693122fab20fc1eed235054ffeEric Dumazettfifo_dequeue: 574aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet skb = __skb_dequeue(&sch->q); 575771018e76aaa6474be20a53c20458bcae8b00485Stephen Hemminger if (skb) { 576aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazetdeliver: 57725331d6ce42bcf4b34b6705fce4da15c3fabe62fJohn Fastabend qdisc_qstats_backlog_dec(sch, skb); 578aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet qdisc_unthrottled(sch); 579aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet qdisc_bstats_update(sch, skb); 580aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet return skb; 581aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet } 582aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet p = rb_first(&q->t_root); 583aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet if (p) { 58436b7bfe09b6deb71bf387852465245783c9a6208Eric Dumazet psched_time_t time_to_send; 58536b7bfe09b6deb71bf387852465245783c9a6208Eric Dumazet 586aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet skb = netem_rb_to_skb(p); 5870f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger 5880f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger /* if more time remaining? */ 58936b7bfe09b6deb71bf387852465245783c9a6208Eric Dumazet time_to_send = netem_skb_cb(skb)->time_to_send; 59036b7bfe09b6deb71bf387852465245783c9a6208Eric Dumazet if (time_to_send <= psched_get_time()) { 591aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet rb_erase(p, &q->t_root); 592aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet 593aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet sch->q.qlen--; 594aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet skb->next = NULL; 595aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet skb->prev = NULL; 596aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet skb->tstamp = netem_skb_cb(skb)->tstamp_save; 59703c05f0d4bb0c267edf12d614025a40e33c5a6f9Jarek Poplawski 5988caf153974f2274301e583fda732cc8e5b80331fJarek Poplawski#ifdef CONFIG_NET_CLS_ACT 5998caf153974f2274301e583fda732cc8e5b80331fJarek Poplawski /* 6008caf153974f2274301e583fda732cc8e5b80331fJarek Poplawski * If it's at ingress let's pretend the delay is 6018caf153974f2274301e583fda732cc8e5b80331fJarek Poplawski * from the network (tstamp will be updated). 6028caf153974f2274301e583fda732cc8e5b80331fJarek Poplawski */ 6038caf153974f2274301e583fda732cc8e5b80331fJarek Poplawski if (G_TC_FROM(skb->tc_verd) & AT_INGRESS) 6048caf153974f2274301e583fda732cc8e5b80331fJarek Poplawski skb->tstamp.tv64 = 0; 6058caf153974f2274301e583fda732cc8e5b80331fJarek Poplawski#endif 60610f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger 60750612537e9ab29693122fab20fc1eed235054ffeEric Dumazet if (q->qdisc) { 60850612537e9ab29693122fab20fc1eed235054ffeEric Dumazet int err = qdisc_enqueue(skb, q->qdisc); 60950612537e9ab29693122fab20fc1eed235054ffeEric Dumazet 61050612537e9ab29693122fab20fc1eed235054ffeEric Dumazet if (unlikely(err != NET_XMIT_SUCCESS)) { 61150612537e9ab29693122fab20fc1eed235054ffeEric Dumazet if (net_xmit_drop_count(err)) { 61225331d6ce42bcf4b34b6705fce4da15c3fabe62fJohn Fastabend qdisc_qstats_drop(sch); 61350612537e9ab29693122fab20fc1eed235054ffeEric Dumazet qdisc_tree_decrease_qlen(sch, 1); 61450612537e9ab29693122fab20fc1eed235054ffeEric Dumazet } 61550612537e9ab29693122fab20fc1eed235054ffeEric Dumazet } 61650612537e9ab29693122fab20fc1eed235054ffeEric Dumazet goto tfifo_dequeue; 61750612537e9ab29693122fab20fc1eed235054ffeEric Dumazet } 618aec0a40a6f78843c0ce73f7398230ee5184f896dEric Dumazet goto deliver; 61907aaa11540828f4482c09e1a936a1f63cdb9fc9dStephen Hemminger } 62011274e5a43266d531140530adebead6903380cafStephen Hemminger 62150612537e9ab29693122fab20fc1eed235054ffeEric Dumazet if (q->qdisc) { 62250612537e9ab29693122fab20fc1eed235054ffeEric Dumazet skb = q->qdisc->ops->dequeue(q->qdisc); 62350612537e9ab29693122fab20fc1eed235054ffeEric Dumazet if (skb) 62450612537e9ab29693122fab20fc1eed235054ffeEric Dumazet goto deliver; 62550612537e9ab29693122fab20fc1eed235054ffeEric Dumazet } 62636b7bfe09b6deb71bf387852465245783c9a6208Eric Dumazet qdisc_watchdog_schedule(&q->watchdog, time_to_send); 6270f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger } 6280f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger 62950612537e9ab29693122fab20fc1eed235054ffeEric Dumazet if (q->qdisc) { 63050612537e9ab29693122fab20fc1eed235054ffeEric Dumazet skb = q->qdisc->ops->dequeue(q->qdisc); 63150612537e9ab29693122fab20fc1eed235054ffeEric Dumazet if (skb) 63250612537e9ab29693122fab20fc1eed235054ffeEric Dumazet goto deliver; 63350612537e9ab29693122fab20fc1eed235054ffeEric Dumazet } 6340f9f32ac65ee4a452a912a8440cebbc4dff73852Stephen Hemminger return NULL; 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void netem_reset(struct Qdisc *sch) 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct netem_sched_data *q = qdisc_priv(sch); 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 64150612537e9ab29693122fab20fc1eed235054ffeEric Dumazet qdisc_reset_queue(sch); 642ff704050f2fc0f3382b5a70bba56a51a3feca79dstephen hemminger tfifo_reset(sch); 64350612537e9ab29693122fab20fc1eed235054ffeEric Dumazet if (q->qdisc) 64450612537e9ab29693122fab20fc1eed235054ffeEric Dumazet qdisc_reset(q->qdisc); 64559cb5c6734021acc68590c7c2e0e92ad9a4952c6Patrick McHardy qdisc_watchdog_cancel(&q->watchdog); 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6486373a9a286bdd955a76924cee88a2f8f784988b1stephen hemmingerstatic void dist_free(struct disttable *d) 6496373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger{ 6504cb28970a23ff209199b0a4358d68efe82c8f493WANG Cong kvfree(d); 6516373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger} 6526373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Distribution data is a variable size payload containing 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * signed 16 bit values. 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6571e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardystatic int get_dist_table(struct Qdisc *sch, const struct nlattr *attr) 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct netem_sched_data *q = qdisc_priv(sch); 6606373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger size_t n = nla_len(attr)/sizeof(__s16); 6611e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy const __s16 *data = nla_data(attr); 6627698b4fcabcd790efc4f226bada1e7b5870653afDavid S. Miller spinlock_t *root_lock; 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct disttable *d; 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 6656373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger size_t s; 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 667df173bda2639ac744ccf596ec1f8f7e66fe4c343stephen hemminger if (n > NETEM_DIST_MAX) 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6706373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger s = sizeof(struct disttable) + n * sizeof(s16); 671bb52c7acf871537a468433775151339f783d2e8cEric Dumazet d = kmalloc(s, GFP_KERNEL | __GFP_NOWARN); 6726373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger if (!d) 6736373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger d = vmalloc(s); 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!d) 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds d->size = n; 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < n; i++) 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds d->table[i] = data[i]; 68010297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki 681102396ae65108b026e4e1868e30fa013f45a169eJarek Poplawski root_lock = qdisc_root_sleeping_lock(sch); 6827698b4fcabcd790efc4f226bada1e7b5870653afDavid S. Miller 6837698b4fcabcd790efc4f226bada1e7b5870653afDavid S. Miller spin_lock_bh(root_lock); 684bb52c7acf871537a468433775151339f783d2e8cEric Dumazet swap(q->delay_dist, d); 6857698b4fcabcd790efc4f226bada1e7b5870653afDavid S. Miller spin_unlock_bh(root_lock); 686bb52c7acf871537a468433775151339f783d2e8cEric Dumazet 687bb52c7acf871537a468433775151339f783d2e8cEric Dumazet dist_free(d); 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 69149545a7775e746e4e32d1524801221ffdfe1cc0aYang Yingliangstatic void get_correlation(struct netem_sched_data *q, const struct nlattr *attr) 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6931e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy const struct tc_netem_corr *c = nla_data(attr); 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_crandom(&q->delay_cor, c->delay_corr); 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_crandom(&q->loss_cor, c->loss_corr); 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_crandom(&q->dup_cor, c->dup_corr); 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 70049545a7775e746e4e32d1524801221ffdfe1cc0aYang Yingliangstatic void get_reorder(struct netem_sched_data *q, const struct nlattr *attr) 7010dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger{ 7021e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy const struct tc_netem_reorder *r = nla_data(attr); 7030dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger 7040dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger q->reorder = r->probability; 7050dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger init_crandom(&q->reorder_cor, r->correlation); 7060dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger} 7070dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger 70849545a7775e746e4e32d1524801221ffdfe1cc0aYang Yingliangstatic void get_corrupt(struct netem_sched_data *q, const struct nlattr *attr) 709c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger{ 7101e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardy const struct tc_netem_corrupt *r = nla_data(attr); 711c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger 712c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger q->corrupt = r->probability; 713c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger init_crandom(&q->corrupt_cor, r->correlation); 714c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger} 715c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger 71649545a7775e746e4e32d1524801221ffdfe1cc0aYang Yingliangstatic void get_rate(struct netem_sched_data *q, const struct nlattr *attr) 7177bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer{ 7187bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer const struct tc_netem_rate *r = nla_data(attr); 7197bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer 7207bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer q->rate = r->rate; 72190b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer q->packet_overhead = r->packet_overhead; 72290b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer q->cell_size = r->cell_size; 723809fa972fd90ff27225294b17a027e908b2d7b7aHannes Frederic Sowa q->cell_overhead = r->cell_overhead; 72490b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer if (q->cell_size) 72590b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer q->cell_size_reciprocal = reciprocal_value(q->cell_size); 726809fa972fd90ff27225294b17a027e908b2d7b7aHannes Frederic Sowa else 727809fa972fd90ff27225294b17a027e908b2d7b7aHannes Frederic Sowa q->cell_size_reciprocal = (struct reciprocal_value) { 0 }; 7287bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer} 7297bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer 73049545a7775e746e4e32d1524801221ffdfe1cc0aYang Yingliangstatic int get_loss_clg(struct netem_sched_data *q, const struct nlattr *attr) 731661b79725fea030803a89a16cda506bac8eeca78stephen hemminger{ 732661b79725fea030803a89a16cda506bac8eeca78stephen hemminger const struct nlattr *la; 733661b79725fea030803a89a16cda506bac8eeca78stephen hemminger int rem; 734661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 735661b79725fea030803a89a16cda506bac8eeca78stephen hemminger nla_for_each_nested(la, attr, rem) { 736661b79725fea030803a89a16cda506bac8eeca78stephen hemminger u16 type = nla_type(la); 737661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 738833fa7438659d768f0aee862aab4a30cde362bbfYang Yingliang switch (type) { 739661b79725fea030803a89a16cda506bac8eeca78stephen hemminger case NETEM_LOSS_GI: { 740661b79725fea030803a89a16cda506bac8eeca78stephen hemminger const struct tc_netem_gimodel *gi = nla_data(la); 741661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 7422494654d4890316e7340fb8b3458daad0474a1b9stephen hemminger if (nla_len(la) < sizeof(struct tc_netem_gimodel)) { 743661b79725fea030803a89a16cda506bac8eeca78stephen hemminger pr_info("netem: incorrect gi model size\n"); 744661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return -EINVAL; 745661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } 746661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 747661b79725fea030803a89a16cda506bac8eeca78stephen hemminger q->loss_model = CLG_4_STATES; 748661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 7493fbac2a87e73e1dfdfa83e18e9601628eec0d676Yang Yingliang q->clg.state = TX_IN_GAP_PERIOD; 750661b79725fea030803a89a16cda506bac8eeca78stephen hemminger q->clg.a1 = gi->p13; 751661b79725fea030803a89a16cda506bac8eeca78stephen hemminger q->clg.a2 = gi->p31; 752661b79725fea030803a89a16cda506bac8eeca78stephen hemminger q->clg.a3 = gi->p32; 753661b79725fea030803a89a16cda506bac8eeca78stephen hemminger q->clg.a4 = gi->p14; 754661b79725fea030803a89a16cda506bac8eeca78stephen hemminger q->clg.a5 = gi->p23; 755661b79725fea030803a89a16cda506bac8eeca78stephen hemminger break; 756661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } 757661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 758661b79725fea030803a89a16cda506bac8eeca78stephen hemminger case NETEM_LOSS_GE: { 759661b79725fea030803a89a16cda506bac8eeca78stephen hemminger const struct tc_netem_gemodel *ge = nla_data(la); 760661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 7612494654d4890316e7340fb8b3458daad0474a1b9stephen hemminger if (nla_len(la) < sizeof(struct tc_netem_gemodel)) { 7622494654d4890316e7340fb8b3458daad0474a1b9stephen hemminger pr_info("netem: incorrect ge model size\n"); 763661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return -EINVAL; 764661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } 765661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 766661b79725fea030803a89a16cda506bac8eeca78stephen hemminger q->loss_model = CLG_GILB_ELL; 7673fbac2a87e73e1dfdfa83e18e9601628eec0d676Yang Yingliang q->clg.state = GOOD_STATE; 768661b79725fea030803a89a16cda506bac8eeca78stephen hemminger q->clg.a1 = ge->p; 769661b79725fea030803a89a16cda506bac8eeca78stephen hemminger q->clg.a2 = ge->r; 770661b79725fea030803a89a16cda506bac8eeca78stephen hemminger q->clg.a3 = ge->h; 771661b79725fea030803a89a16cda506bac8eeca78stephen hemminger q->clg.a4 = ge->k1; 772661b79725fea030803a89a16cda506bac8eeca78stephen hemminger break; 773661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } 774661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 775661b79725fea030803a89a16cda506bac8eeca78stephen hemminger default: 776661b79725fea030803a89a16cda506bac8eeca78stephen hemminger pr_info("netem: unknown loss type %u\n", type); 777661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return -EINVAL; 778661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } 779661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } 780661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 781661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return 0; 782661b79725fea030803a89a16cda506bac8eeca78stephen hemminger} 783661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 78427a3421e4821734bc19496faa77b380605dc3b23Patrick McHardystatic const struct nla_policy netem_policy[TCA_NETEM_MAX + 1] = { 78527a3421e4821734bc19496faa77b380605dc3b23Patrick McHardy [TCA_NETEM_CORR] = { .len = sizeof(struct tc_netem_corr) }, 78627a3421e4821734bc19496faa77b380605dc3b23Patrick McHardy [TCA_NETEM_REORDER] = { .len = sizeof(struct tc_netem_reorder) }, 78727a3421e4821734bc19496faa77b380605dc3b23Patrick McHardy [TCA_NETEM_CORRUPT] = { .len = sizeof(struct tc_netem_corrupt) }, 7887bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer [TCA_NETEM_RATE] = { .len = sizeof(struct tc_netem_rate) }, 789661b79725fea030803a89a16cda506bac8eeca78stephen hemminger [TCA_NETEM_LOSS] = { .type = NLA_NESTED }, 790e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet [TCA_NETEM_ECN] = { .type = NLA_U32 }, 7916a031f67c83aa175aedd10d4ae64750415ab57b0Yang Yingliang [TCA_NETEM_RATE64] = { .type = NLA_U64 }, 79227a3421e4821734bc19496faa77b380605dc3b23Patrick McHardy}; 79327a3421e4821734bc19496faa77b380605dc3b23Patrick McHardy 7942c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Grafstatic int parse_attr(struct nlattr *tb[], int maxtype, struct nlattr *nla, 7952c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf const struct nla_policy *policy, int len) 7962c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf{ 7972c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf int nested_len = nla_len(nla) - NLA_ALIGN(len); 7982c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf 799661b79725fea030803a89a16cda506bac8eeca78stephen hemminger if (nested_len < 0) { 800661b79725fea030803a89a16cda506bac8eeca78stephen hemminger pr_info("netem: invalid attributes len %d\n", nested_len); 8012c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf return -EINVAL; 802661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } 803661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 8042c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf if (nested_len >= nla_attr_size(0)) 8052c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf return nla_parse(tb, maxtype, nla_data(nla) + NLA_ALIGN(len), 8062c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf nested_len, policy); 807661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 8082c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1)); 8092c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf return 0; 8102c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf} 8112c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf 812c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger/* Parse netlink message to set options */ 8131e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardystatic int netem_change(struct Qdisc *sch, struct nlattr *opt) 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct netem_sched_data *q = qdisc_priv(sch); 816b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy struct nlattr *tb[TCA_NETEM_MAX + 1]; 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tc_netem_qopt *qopt; 81854a4b05cd281a352d803417a98a72878fb0802cfYang Yingliang struct clgstate old_clg; 81954a4b05cd281a352d803417a98a72878fb0802cfYang Yingliang int old_loss_model = CLG_RANDOM; 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 82110297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki 822b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy if (opt == NULL) 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8252c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf qopt = nla_data(opt); 8262c10b32bf57db7ec6d4cca4c4aa3d86bacb01c8aThomas Graf ret = parse_attr(tb, TCA_NETEM_MAX, opt, netem_policy, sizeof(*qopt)); 827b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy if (ret < 0) 828b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy return ret; 829b03f4672007e533c8dbf0965f995182586216bf1Patrick McHardy 83054a4b05cd281a352d803417a98a72878fb0802cfYang Yingliang /* backup q->clg and q->loss_model */ 83154a4b05cd281a352d803417a98a72878fb0802cfYang Yingliang old_clg = q->clg; 83254a4b05cd281a352d803417a98a72878fb0802cfYang Yingliang old_loss_model = q->loss_model; 83354a4b05cd281a352d803417a98a72878fb0802cfYang Yingliang 83454a4b05cd281a352d803417a98a72878fb0802cfYang Yingliang if (tb[TCA_NETEM_LOSS]) { 83549545a7775e746e4e32d1524801221ffdfe1cc0aYang Yingliang ret = get_loss_clg(q, tb[TCA_NETEM_LOSS]); 83654a4b05cd281a352d803417a98a72878fb0802cfYang Yingliang if (ret) { 83754a4b05cd281a352d803417a98a72878fb0802cfYang Yingliang q->loss_model = old_loss_model; 83854a4b05cd281a352d803417a98a72878fb0802cfYang Yingliang return ret; 83954a4b05cd281a352d803417a98a72878fb0802cfYang Yingliang } 84054a4b05cd281a352d803417a98a72878fb0802cfYang Yingliang } else { 84154a4b05cd281a352d803417a98a72878fb0802cfYang Yingliang q->loss_model = CLG_RANDOM; 84254a4b05cd281a352d803417a98a72878fb0802cfYang Yingliang } 84354a4b05cd281a352d803417a98a72878fb0802cfYang Yingliang 84454a4b05cd281a352d803417a98a72878fb0802cfYang Yingliang if (tb[TCA_NETEM_DELAY_DIST]) { 84554a4b05cd281a352d803417a98a72878fb0802cfYang Yingliang ret = get_dist_table(sch, tb[TCA_NETEM_DELAY_DIST]); 84654a4b05cd281a352d803417a98a72878fb0802cfYang Yingliang if (ret) { 84754a4b05cd281a352d803417a98a72878fb0802cfYang Yingliang /* recover clg and loss_model, in case of 84854a4b05cd281a352d803417a98a72878fb0802cfYang Yingliang * q->clg and q->loss_model were modified 84954a4b05cd281a352d803417a98a72878fb0802cfYang Yingliang * in get_loss_clg() 85054a4b05cd281a352d803417a98a72878fb0802cfYang Yingliang */ 85154a4b05cd281a352d803417a98a72878fb0802cfYang Yingliang q->clg = old_clg; 85254a4b05cd281a352d803417a98a72878fb0802cfYang Yingliang q->loss_model = old_loss_model; 85354a4b05cd281a352d803417a98a72878fb0802cfYang Yingliang return ret; 85454a4b05cd281a352d803417a98a72878fb0802cfYang Yingliang } 85554a4b05cd281a352d803417a98a72878fb0802cfYang Yingliang } 85654a4b05cd281a352d803417a98a72878fb0802cfYang Yingliang 85750612537e9ab29693122fab20fc1eed235054ffeEric Dumazet sch->limit = qopt->limit; 85810297b99315e5e08fe623ba56da35db1fee69ba9YOSHIFUJI Hideaki 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q->latency = qopt->latency; 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q->jitter = qopt->jitter; 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q->limit = qopt->limit; 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q->gap = qopt->gap; 8630dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger q->counter = 0; 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q->loss = qopt->loss; 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds q->duplicate = qopt->duplicate; 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 867bb2f8cc0ecf025d6d3947e0389434650023f432eStephen Hemminger /* for compatibility with earlier versions. 868bb2f8cc0ecf025d6d3947e0389434650023f432eStephen Hemminger * if gap is set, need to assume 100% probability 8690dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger */ 870a362e0a7890c735a3ef63aab12d71ecfc6e6f4a5Stephen Hemminger if (q->gap) 871a362e0a7890c735a3ef63aab12d71ecfc6e6f4a5Stephen Hemminger q->reorder = ~0; 8720dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger 873265eb67fb4e16be8e46a51e1e4e2ecd99fb15219Stephen Hemminger if (tb[TCA_NETEM_CORR]) 87449545a7775e746e4e32d1524801221ffdfe1cc0aYang Yingliang get_correlation(q, tb[TCA_NETEM_CORR]); 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 876265eb67fb4e16be8e46a51e1e4e2ecd99fb15219Stephen Hemminger if (tb[TCA_NETEM_REORDER]) 87749545a7775e746e4e32d1524801221ffdfe1cc0aYang Yingliang get_reorder(q, tb[TCA_NETEM_REORDER]); 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 879265eb67fb4e16be8e46a51e1e4e2ecd99fb15219Stephen Hemminger if (tb[TCA_NETEM_CORRUPT]) 88049545a7775e746e4e32d1524801221ffdfe1cc0aYang Yingliang get_corrupt(q, tb[TCA_NETEM_CORRUPT]); 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8827bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer if (tb[TCA_NETEM_RATE]) 88349545a7775e746e4e32d1524801221ffdfe1cc0aYang Yingliang get_rate(q, tb[TCA_NETEM_RATE]); 8847bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer 8856a031f67c83aa175aedd10d4ae64750415ab57b0Yang Yingliang if (tb[TCA_NETEM_RATE64]) 8866a031f67c83aa175aedd10d4ae64750415ab57b0Yang Yingliang q->rate = max_t(u64, q->rate, 8876a031f67c83aa175aedd10d4ae64750415ab57b0Yang Yingliang nla_get_u64(tb[TCA_NETEM_RATE64])); 8886a031f67c83aa175aedd10d4ae64750415ab57b0Yang Yingliang 889e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet if (tb[TCA_NETEM_ECN]) 890e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet q->ecn = nla_get_u32(tb[TCA_NETEM_ECN]); 891e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet 892661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return ret; 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8951e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardystatic int netem_init(struct Qdisc *sch, struct nlattr *opt) 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct netem_sched_data *q = qdisc_priv(sch); 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!opt) 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 90359cb5c6734021acc68590c7c2e0e92ad9a4952c6Patrick McHardy qdisc_watchdog_init(&q->watchdog, sch); 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 905661b79725fea030803a89a16cda506bac8eeca78stephen hemminger q->loss_model = CLG_RANDOM; 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = netem_change(sch, opt); 90750612537e9ab29693122fab20fc1eed235054ffeEric Dumazet if (ret) 908250a65f78265940ac33a2dd2002924e6126efe14stephen hemminger pr_info("netem: change failed\n"); 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void netem_destroy(struct Qdisc *sch) 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct netem_sched_data *q = qdisc_priv(sch); 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 91659cb5c6734021acc68590c7c2e0e92ad9a4952c6Patrick McHardy qdisc_watchdog_cancel(&q->watchdog); 91750612537e9ab29693122fab20fc1eed235054ffeEric Dumazet if (q->qdisc) 91850612537e9ab29693122fab20fc1eed235054ffeEric Dumazet qdisc_destroy(q->qdisc); 9196373a9a286bdd955a76924cee88a2f8f784988b1stephen hemminger dist_free(q->delay_dist); 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 922661b79725fea030803a89a16cda506bac8eeca78stephen hemmingerstatic int dump_loss_model(const struct netem_sched_data *q, 923661b79725fea030803a89a16cda506bac8eeca78stephen hemminger struct sk_buff *skb) 924661b79725fea030803a89a16cda506bac8eeca78stephen hemminger{ 925661b79725fea030803a89a16cda506bac8eeca78stephen hemminger struct nlattr *nest; 926661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 927661b79725fea030803a89a16cda506bac8eeca78stephen hemminger nest = nla_nest_start(skb, TCA_NETEM_LOSS); 928661b79725fea030803a89a16cda506bac8eeca78stephen hemminger if (nest == NULL) 929661b79725fea030803a89a16cda506bac8eeca78stephen hemminger goto nla_put_failure; 930661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 931661b79725fea030803a89a16cda506bac8eeca78stephen hemminger switch (q->loss_model) { 932661b79725fea030803a89a16cda506bac8eeca78stephen hemminger case CLG_RANDOM: 933661b79725fea030803a89a16cda506bac8eeca78stephen hemminger /* legacy loss model */ 934661b79725fea030803a89a16cda506bac8eeca78stephen hemminger nla_nest_cancel(skb, nest); 935661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return 0; /* no data */ 936661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 937661b79725fea030803a89a16cda506bac8eeca78stephen hemminger case CLG_4_STATES: { 938661b79725fea030803a89a16cda506bac8eeca78stephen hemminger struct tc_netem_gimodel gi = { 939661b79725fea030803a89a16cda506bac8eeca78stephen hemminger .p13 = q->clg.a1, 940661b79725fea030803a89a16cda506bac8eeca78stephen hemminger .p31 = q->clg.a2, 941661b79725fea030803a89a16cda506bac8eeca78stephen hemminger .p32 = q->clg.a3, 942661b79725fea030803a89a16cda506bac8eeca78stephen hemminger .p14 = q->clg.a4, 943661b79725fea030803a89a16cda506bac8eeca78stephen hemminger .p23 = q->clg.a5, 944661b79725fea030803a89a16cda506bac8eeca78stephen hemminger }; 945661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 9461b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller if (nla_put(skb, NETEM_LOSS_GI, sizeof(gi), &gi)) 9471b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller goto nla_put_failure; 948661b79725fea030803a89a16cda506bac8eeca78stephen hemminger break; 949661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } 950661b79725fea030803a89a16cda506bac8eeca78stephen hemminger case CLG_GILB_ELL: { 951661b79725fea030803a89a16cda506bac8eeca78stephen hemminger struct tc_netem_gemodel ge = { 952661b79725fea030803a89a16cda506bac8eeca78stephen hemminger .p = q->clg.a1, 953661b79725fea030803a89a16cda506bac8eeca78stephen hemminger .r = q->clg.a2, 954661b79725fea030803a89a16cda506bac8eeca78stephen hemminger .h = q->clg.a3, 955661b79725fea030803a89a16cda506bac8eeca78stephen hemminger .k1 = q->clg.a4, 956661b79725fea030803a89a16cda506bac8eeca78stephen hemminger }; 957661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 9581b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller if (nla_put(skb, NETEM_LOSS_GE, sizeof(ge), &ge)) 9591b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller goto nla_put_failure; 960661b79725fea030803a89a16cda506bac8eeca78stephen hemminger break; 961661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } 962661b79725fea030803a89a16cda506bac8eeca78stephen hemminger } 963661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 964661b79725fea030803a89a16cda506bac8eeca78stephen hemminger nla_nest_end(skb, nest); 965661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return 0; 966661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 967661b79725fea030803a89a16cda506bac8eeca78stephen hemmingernla_put_failure: 968661b79725fea030803a89a16cda506bac8eeca78stephen hemminger nla_nest_cancel(skb, nest); 969661b79725fea030803a89a16cda506bac8eeca78stephen hemminger return -1; 970661b79725fea030803a89a16cda506bac8eeca78stephen hemminger} 971661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int netem_dump(struct Qdisc *sch, struct sk_buff *skb) 9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct netem_sched_data *q = qdisc_priv(sch); 975861d7f745f37506bbd90227e97b95baf2a5fac34stephen hemminger struct nlattr *nla = (struct nlattr *) skb_tail_pointer(skb); 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tc_netem_qopt qopt; 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct tc_netem_corr cor; 9780dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger struct tc_netem_reorder reorder; 979c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger struct tc_netem_corrupt corrupt; 9807bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer struct tc_netem_rate rate; 9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qopt.latency = q->latency; 9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qopt.jitter = q->jitter; 9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qopt.limit = q->limit; 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qopt.loss = q->loss; 9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qopt.gap = q->gap; 9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qopt.duplicate = q->duplicate; 9881b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller if (nla_put(skb, TCA_OPTIONS, sizeof(qopt), &qopt)) 9891b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller goto nla_put_failure; 9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cor.delay_corr = q->delay_cor.rho; 9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cor.loss_corr = q->loss_cor.rho; 9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cor.dup_corr = q->dup_cor.rho; 9941b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller if (nla_put(skb, TCA_NETEM_CORR, sizeof(cor), &cor)) 9951b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller goto nla_put_failure; 9960dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger 9970dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger reorder.probability = q->reorder; 9980dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger reorder.correlation = q->reorder_cor.rho; 9991b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller if (nla_put(skb, TCA_NETEM_REORDER, sizeof(reorder), &reorder)) 10001b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller goto nla_put_failure; 10010dca51d362b8e4af6b0dbc9e54d1e5165341918aStephen Hemminger 1002c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger corrupt.probability = q->corrupt; 1003c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger corrupt.correlation = q->corrupt_cor.rho; 10041b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller if (nla_put(skb, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt)) 10051b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller goto nla_put_failure; 1006c865e5d99e25a171e8262fc0f7ba608568633c64Stephen Hemminger 10076a031f67c83aa175aedd10d4ae64750415ab57b0Yang Yingliang if (q->rate >= (1ULL << 32)) { 10086a031f67c83aa175aedd10d4ae64750415ab57b0Yang Yingliang if (nla_put_u64(skb, TCA_NETEM_RATE64, q->rate)) 10096a031f67c83aa175aedd10d4ae64750415ab57b0Yang Yingliang goto nla_put_failure; 10106a031f67c83aa175aedd10d4ae64750415ab57b0Yang Yingliang rate.rate = ~0U; 10116a031f67c83aa175aedd10d4ae64750415ab57b0Yang Yingliang } else { 10126a031f67c83aa175aedd10d4ae64750415ab57b0Yang Yingliang rate.rate = q->rate; 10136a031f67c83aa175aedd10d4ae64750415ab57b0Yang Yingliang } 101490b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer rate.packet_overhead = q->packet_overhead; 101590b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer rate.cell_size = q->cell_size; 101690b41a1cd44cc4e507b554ae5a36562a1ba9a4e8Hagen Paul Pfeifer rate.cell_overhead = q->cell_overhead; 10171b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller if (nla_put(skb, TCA_NETEM_RATE, sizeof(rate), &rate)) 10181b34ec43c9b3de44a5420841ab293d1b2035a94cDavid S. Miller goto nla_put_failure; 10197bc0f28c7a0cd19f40e5a6e4d0a117db9a4e4cd5Hagen Paul Pfeifer 1020e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet if (q->ecn && nla_put_u32(skb, TCA_NETEM_ECN, q->ecn)) 1021e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet goto nla_put_failure; 1022e4ae004b84b315dd4b762e474f97403eac70f76aEric Dumazet 1023661b79725fea030803a89a16cda506bac8eeca78stephen hemminger if (dump_loss_model(q, skb) != 0) 1024661b79725fea030803a89a16cda506bac8eeca78stephen hemminger goto nla_put_failure; 1025661b79725fea030803a89a16cda506bac8eeca78stephen hemminger 1026861d7f745f37506bbd90227e97b95baf2a5fac34stephen hemminger return nla_nest_end(skb, nla); 10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10281e90474c377e92db7262a8968a45c1dd980ca9e5Patrick McHardynla_put_failure: 1029861d7f745f37506bbd90227e97b95baf2a5fac34stephen hemminger nlmsg_trim(skb, nla); 10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 103310f6dfcfde884441db89dc66b945d6c948e1d356stephen hemmingerstatic int netem_dump_class(struct Qdisc *sch, unsigned long cl, 103410f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger struct sk_buff *skb, struct tcmsg *tcm) 103510f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger{ 103610f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger struct netem_sched_data *q = qdisc_priv(sch); 103710f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger 103850612537e9ab29693122fab20fc1eed235054ffeEric Dumazet if (cl != 1 || !q->qdisc) /* only one class */ 103910f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger return -ENOENT; 104010f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger 104110f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger tcm->tcm_handle |= TC_H_MIN(1); 104210f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger tcm->tcm_info = q->qdisc->handle; 104310f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger 104410f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger return 0; 104510f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger} 104610f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger 104710f6dfcfde884441db89dc66b945d6c948e1d356stephen hemmingerstatic int netem_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, 104810f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger struct Qdisc **old) 104910f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger{ 105010f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger struct netem_sched_data *q = qdisc_priv(sch); 105110f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger 105210f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger sch_tree_lock(sch); 105310f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger *old = q->qdisc; 105410f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger q->qdisc = new; 105550612537e9ab29693122fab20fc1eed235054ffeEric Dumazet if (*old) { 105650612537e9ab29693122fab20fc1eed235054ffeEric Dumazet qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); 105750612537e9ab29693122fab20fc1eed235054ffeEric Dumazet qdisc_reset(*old); 105850612537e9ab29693122fab20fc1eed235054ffeEric Dumazet } 105910f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger sch_tree_unlock(sch); 106010f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger 106110f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger return 0; 106210f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger} 106310f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger 106410f6dfcfde884441db89dc66b945d6c948e1d356stephen hemmingerstatic struct Qdisc *netem_leaf(struct Qdisc *sch, unsigned long arg) 106510f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger{ 106610f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger struct netem_sched_data *q = qdisc_priv(sch); 106710f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger return q->qdisc; 106810f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger} 106910f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger 107010f6dfcfde884441db89dc66b945d6c948e1d356stephen hemmingerstatic unsigned long netem_get(struct Qdisc *sch, u32 classid) 107110f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger{ 107210f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger return 1; 107310f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger} 107410f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger 107510f6dfcfde884441db89dc66b945d6c948e1d356stephen hemmingerstatic void netem_put(struct Qdisc *sch, unsigned long arg) 107610f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger{ 107710f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger} 107810f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger 107910f6dfcfde884441db89dc66b945d6c948e1d356stephen hemmingerstatic void netem_walk(struct Qdisc *sch, struct qdisc_walker *walker) 108010f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger{ 108110f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger if (!walker->stop) { 108210f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger if (walker->count >= walker->skip) 108310f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger if (walker->fn(sch, 1, walker) < 0) { 108410f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger walker->stop = 1; 108510f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger return; 108610f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger } 108710f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger walker->count++; 108810f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger } 108910f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger} 109010f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger 109110f6dfcfde884441db89dc66b945d6c948e1d356stephen hemmingerstatic const struct Qdisc_class_ops netem_class_ops = { 109210f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger .graft = netem_graft, 109310f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger .leaf = netem_leaf, 109410f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger .get = netem_get, 109510f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger .put = netem_put, 109610f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger .walk = netem_walk, 109710f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger .dump = netem_dump_class, 109810f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger}; 109910f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger 110020fea08b5fb639c4c175b5c74a2bb346c5c5bc2eEric Dumazetstatic struct Qdisc_ops netem_qdisc_ops __read_mostly = { 11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id = "netem", 110210f6dfcfde884441db89dc66b945d6c948e1d356stephen hemminger .cl_ops = &netem_class_ops, 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .priv_size = sizeof(struct netem_sched_data), 11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .enqueue = netem_enqueue, 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .dequeue = netem_dequeue, 110677be155cba4e163e8bba9fd27222a8b6189ec4f7Jarek Poplawski .peek = qdisc_peek_dequeued, 11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .drop = netem_drop, 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .init = netem_init, 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .reset = netem_reset, 11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .destroy = netem_destroy, 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .change = netem_change, 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .dump = netem_dump, 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init netem_module_init(void) 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1119eb229c4cdc3389682cda20adb015ba767950a220Stephen Hemminger pr_info("netem: version " VERSION "\n"); 11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return register_qdisc(&netem_qdisc_ops); 11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit netem_module_exit(void) 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unregister_qdisc(&netem_qdisc_ops); 11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(netem_module_init) 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(netem_module_exit) 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 1129