162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * net/sched/sch_netem.c	Network emulator
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  		Many of the algorithms and ideas for this came from
662306a36Sopenharmony_ci *		NIST Net which is not copyrighted.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Authors:	Stephen Hemminger <shemminger@osdl.org>
962306a36Sopenharmony_ci *		Catalin(ux aka Dino) BOIE <catab at umbrella dot ro>
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/mm.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/slab.h>
1562306a36Sopenharmony_ci#include <linux/types.h>
1662306a36Sopenharmony_ci#include <linux/kernel.h>
1762306a36Sopenharmony_ci#include <linux/errno.h>
1862306a36Sopenharmony_ci#include <linux/skbuff.h>
1962306a36Sopenharmony_ci#include <linux/vmalloc.h>
2062306a36Sopenharmony_ci#include <linux/rtnetlink.h>
2162306a36Sopenharmony_ci#include <linux/reciprocal_div.h>
2262306a36Sopenharmony_ci#include <linux/rbtree.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include <net/gso.h>
2562306a36Sopenharmony_ci#include <net/netlink.h>
2662306a36Sopenharmony_ci#include <net/pkt_sched.h>
2762306a36Sopenharmony_ci#include <net/inet_ecn.h>
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#define VERSION "1.3"
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci/*	Network Emulation Queuing algorithm.
3262306a36Sopenharmony_ci	====================================
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	Sources: [1] Mark Carson, Darrin Santay, "NIST Net - A Linux-based
3562306a36Sopenharmony_ci		 Network Emulation Tool
3662306a36Sopenharmony_ci		 [2] Luigi Rizzo, DummyNet for FreeBSD
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	 ----------------------------------------------------------------
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	 This started out as a simple way to delay outgoing packets to
4162306a36Sopenharmony_ci	 test TCP but has grown to include most of the functionality
4262306a36Sopenharmony_ci	 of a full blown network emulator like NISTnet. It can delay
4362306a36Sopenharmony_ci	 packets and add random jitter (and correlation). The random
4462306a36Sopenharmony_ci	 distribution can be loaded from a table as well to provide
4562306a36Sopenharmony_ci	 normal, Pareto, or experimental curves. Packet loss,
4662306a36Sopenharmony_ci	 duplication, and reordering can also be emulated.
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	 This qdisc does not do classification that can be handled in
4962306a36Sopenharmony_ci	 layering other disciplines.  It does not need to do bandwidth
5062306a36Sopenharmony_ci	 control either since that can be handled by using token
5162306a36Sopenharmony_ci	 bucket or other rate control.
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci     Correlated Loss Generator models
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	Added generation of correlated loss according to the
5662306a36Sopenharmony_ci	"Gilbert-Elliot" model, a 4-state markov model.
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	References:
5962306a36Sopenharmony_ci	[1] NetemCLG Home http://netgroup.uniroma2.it/NetemCLG
6062306a36Sopenharmony_ci	[2] S. Salsano, F. Ludovici, A. Ordine, "Definition of a general
6162306a36Sopenharmony_ci	and intuitive loss model for packet networks and its implementation
6262306a36Sopenharmony_ci	in the Netem module in the Linux kernel", available in [1]
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	Authors: Stefano Salsano <stefano.salsano at uniroma2.it
6562306a36Sopenharmony_ci		 Fabio Ludovici <fabio.ludovici at yahoo.it>
6662306a36Sopenharmony_ci*/
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistruct disttable {
6962306a36Sopenharmony_ci	u32  size;
7062306a36Sopenharmony_ci	s16 table[];
7162306a36Sopenharmony_ci};
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistruct netem_sched_data {
7462306a36Sopenharmony_ci	/* internal t(ime)fifo qdisc uses t_root and sch->limit */
7562306a36Sopenharmony_ci	struct rb_root t_root;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	/* a linear queue; reduces rbtree rebalancing when jitter is low */
7862306a36Sopenharmony_ci	struct sk_buff	*t_head;
7962306a36Sopenharmony_ci	struct sk_buff	*t_tail;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	/* optional qdisc for classful handling (NULL at netem init) */
8262306a36Sopenharmony_ci	struct Qdisc	*qdisc;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	struct qdisc_watchdog watchdog;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	s64 latency;
8762306a36Sopenharmony_ci	s64 jitter;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	u32 loss;
9062306a36Sopenharmony_ci	u32 ecn;
9162306a36Sopenharmony_ci	u32 limit;
9262306a36Sopenharmony_ci	u32 counter;
9362306a36Sopenharmony_ci	u32 gap;
9462306a36Sopenharmony_ci	u32 duplicate;
9562306a36Sopenharmony_ci	u32 reorder;
9662306a36Sopenharmony_ci	u32 corrupt;
9762306a36Sopenharmony_ci	u64 rate;
9862306a36Sopenharmony_ci	s32 packet_overhead;
9962306a36Sopenharmony_ci	u32 cell_size;
10062306a36Sopenharmony_ci	struct reciprocal_value cell_size_reciprocal;
10162306a36Sopenharmony_ci	s32 cell_overhead;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	struct crndstate {
10462306a36Sopenharmony_ci		u32 last;
10562306a36Sopenharmony_ci		u32 rho;
10662306a36Sopenharmony_ci	} delay_cor, loss_cor, dup_cor, reorder_cor, corrupt_cor;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	struct prng  {
10962306a36Sopenharmony_ci		u64 seed;
11062306a36Sopenharmony_ci		struct rnd_state prng_state;
11162306a36Sopenharmony_ci	} prng;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	struct disttable *delay_dist;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	enum  {
11662306a36Sopenharmony_ci		CLG_RANDOM,
11762306a36Sopenharmony_ci		CLG_4_STATES,
11862306a36Sopenharmony_ci		CLG_GILB_ELL,
11962306a36Sopenharmony_ci	} loss_model;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	enum {
12262306a36Sopenharmony_ci		TX_IN_GAP_PERIOD = 1,
12362306a36Sopenharmony_ci		TX_IN_BURST_PERIOD,
12462306a36Sopenharmony_ci		LOST_IN_GAP_PERIOD,
12562306a36Sopenharmony_ci		LOST_IN_BURST_PERIOD,
12662306a36Sopenharmony_ci	} _4_state_model;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	enum {
12962306a36Sopenharmony_ci		GOOD_STATE = 1,
13062306a36Sopenharmony_ci		BAD_STATE,
13162306a36Sopenharmony_ci	} GE_state_model;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	/* Correlated Loss Generation models */
13462306a36Sopenharmony_ci	struct clgstate {
13562306a36Sopenharmony_ci		/* state of the Markov chain */
13662306a36Sopenharmony_ci		u8 state;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci		/* 4-states and Gilbert-Elliot models */
13962306a36Sopenharmony_ci		u32 a1;	/* p13 for 4-states or p for GE */
14062306a36Sopenharmony_ci		u32 a2;	/* p31 for 4-states or r for GE */
14162306a36Sopenharmony_ci		u32 a3;	/* p32 for 4-states or h for GE */
14262306a36Sopenharmony_ci		u32 a4;	/* p14 for 4-states or 1-k for GE */
14362306a36Sopenharmony_ci		u32 a5; /* p23 used only in 4-states */
14462306a36Sopenharmony_ci	} clg;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	struct tc_netem_slot slot_config;
14762306a36Sopenharmony_ci	struct slotstate {
14862306a36Sopenharmony_ci		u64 slot_next;
14962306a36Sopenharmony_ci		s32 packets_left;
15062306a36Sopenharmony_ci		s32 bytes_left;
15162306a36Sopenharmony_ci	} slot;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	struct disttable *slot_dist;
15462306a36Sopenharmony_ci};
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci/* Time stamp put into socket buffer control block
15762306a36Sopenharmony_ci * Only valid when skbs are in our internal t(ime)fifo queue.
15862306a36Sopenharmony_ci *
15962306a36Sopenharmony_ci * As skb->rbnode uses same storage than skb->next, skb->prev and skb->tstamp,
16062306a36Sopenharmony_ci * and skb->next & skb->prev are scratch space for a qdisc,
16162306a36Sopenharmony_ci * we save skb->tstamp value in skb->cb[] before destroying it.
16262306a36Sopenharmony_ci */
16362306a36Sopenharmony_cistruct netem_skb_cb {
16462306a36Sopenharmony_ci	u64	        time_to_send;
16562306a36Sopenharmony_ci};
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_cistatic inline struct netem_skb_cb *netem_skb_cb(struct sk_buff *skb)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	/* we assume we can use skb next/prev/tstamp as storage for rb_node */
17062306a36Sopenharmony_ci	qdisc_cb_private_validate(skb, sizeof(struct netem_skb_cb));
17162306a36Sopenharmony_ci	return (struct netem_skb_cb *)qdisc_skb_cb(skb)->data;
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci/* init_crandom - initialize correlated random number generator
17562306a36Sopenharmony_ci * Use entropy source for initial seed.
17662306a36Sopenharmony_ci */
17762306a36Sopenharmony_cistatic void init_crandom(struct crndstate *state, unsigned long rho)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	state->rho = rho;
18062306a36Sopenharmony_ci	state->last = get_random_u32();
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci/* get_crandom - correlated random number generator
18462306a36Sopenharmony_ci * Next number depends on last value.
18562306a36Sopenharmony_ci * rho is scaled to avoid floating point.
18662306a36Sopenharmony_ci */
18762306a36Sopenharmony_cistatic u32 get_crandom(struct crndstate *state, struct prng *p)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	u64 value, rho;
19062306a36Sopenharmony_ci	unsigned long answer;
19162306a36Sopenharmony_ci	struct rnd_state *s = &p->prng_state;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	if (!state || state->rho == 0)	/* no correlation */
19462306a36Sopenharmony_ci		return prandom_u32_state(s);
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	value = prandom_u32_state(s);
19762306a36Sopenharmony_ci	rho = (u64)state->rho + 1;
19862306a36Sopenharmony_ci	answer = (value * ((1ull<<32) - rho) + state->last * rho) >> 32;
19962306a36Sopenharmony_ci	state->last = answer;
20062306a36Sopenharmony_ci	return answer;
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci/* loss_4state - 4-state model loss generator
20462306a36Sopenharmony_ci * Generates losses according to the 4-state Markov chain adopted in
20562306a36Sopenharmony_ci * the GI (General and Intuitive) loss model.
20662306a36Sopenharmony_ci */
20762306a36Sopenharmony_cistatic bool loss_4state(struct netem_sched_data *q)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci	struct clgstate *clg = &q->clg;
21062306a36Sopenharmony_ci	u32 rnd = prandom_u32_state(&q->prng.prng_state);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	/*
21362306a36Sopenharmony_ci	 * Makes a comparison between rnd and the transition
21462306a36Sopenharmony_ci	 * probabilities outgoing from the current state, then decides the
21562306a36Sopenharmony_ci	 * next state and if the next packet has to be transmitted or lost.
21662306a36Sopenharmony_ci	 * The four states correspond to:
21762306a36Sopenharmony_ci	 *   TX_IN_GAP_PERIOD => successfully transmitted packets within a gap period
21862306a36Sopenharmony_ci	 *   LOST_IN_GAP_PERIOD => isolated losses within a gap period
21962306a36Sopenharmony_ci	 *   LOST_IN_BURST_PERIOD => lost packets within a burst period
22062306a36Sopenharmony_ci	 *   TX_IN_BURST_PERIOD => successfully transmitted packets within a burst period
22162306a36Sopenharmony_ci	 */
22262306a36Sopenharmony_ci	switch (clg->state) {
22362306a36Sopenharmony_ci	case TX_IN_GAP_PERIOD:
22462306a36Sopenharmony_ci		if (rnd < clg->a4) {
22562306a36Sopenharmony_ci			clg->state = LOST_IN_GAP_PERIOD;
22662306a36Sopenharmony_ci			return true;
22762306a36Sopenharmony_ci		} else if (clg->a4 < rnd && rnd < clg->a1 + clg->a4) {
22862306a36Sopenharmony_ci			clg->state = LOST_IN_BURST_PERIOD;
22962306a36Sopenharmony_ci			return true;
23062306a36Sopenharmony_ci		} else if (clg->a1 + clg->a4 < rnd) {
23162306a36Sopenharmony_ci			clg->state = TX_IN_GAP_PERIOD;
23262306a36Sopenharmony_ci		}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci		break;
23562306a36Sopenharmony_ci	case TX_IN_BURST_PERIOD:
23662306a36Sopenharmony_ci		if (rnd < clg->a5) {
23762306a36Sopenharmony_ci			clg->state = LOST_IN_BURST_PERIOD;
23862306a36Sopenharmony_ci			return true;
23962306a36Sopenharmony_ci		} else {
24062306a36Sopenharmony_ci			clg->state = TX_IN_BURST_PERIOD;
24162306a36Sopenharmony_ci		}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci		break;
24462306a36Sopenharmony_ci	case LOST_IN_BURST_PERIOD:
24562306a36Sopenharmony_ci		if (rnd < clg->a3)
24662306a36Sopenharmony_ci			clg->state = TX_IN_BURST_PERIOD;
24762306a36Sopenharmony_ci		else if (clg->a3 < rnd && rnd < clg->a2 + clg->a3) {
24862306a36Sopenharmony_ci			clg->state = TX_IN_GAP_PERIOD;
24962306a36Sopenharmony_ci		} else if (clg->a2 + clg->a3 < rnd) {
25062306a36Sopenharmony_ci			clg->state = LOST_IN_BURST_PERIOD;
25162306a36Sopenharmony_ci			return true;
25262306a36Sopenharmony_ci		}
25362306a36Sopenharmony_ci		break;
25462306a36Sopenharmony_ci	case LOST_IN_GAP_PERIOD:
25562306a36Sopenharmony_ci		clg->state = TX_IN_GAP_PERIOD;
25662306a36Sopenharmony_ci		break;
25762306a36Sopenharmony_ci	}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	return false;
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci/* loss_gilb_ell - Gilbert-Elliot model loss generator
26362306a36Sopenharmony_ci * Generates losses according to the Gilbert-Elliot loss model or
26462306a36Sopenharmony_ci * its special cases  (Gilbert or Simple Gilbert)
26562306a36Sopenharmony_ci *
26662306a36Sopenharmony_ci * Makes a comparison between random number and the transition
26762306a36Sopenharmony_ci * probabilities outgoing from the current state, then decides the
26862306a36Sopenharmony_ci * next state. A second random number is extracted and the comparison
26962306a36Sopenharmony_ci * with the loss probability of the current state decides if the next
27062306a36Sopenharmony_ci * packet will be transmitted or lost.
27162306a36Sopenharmony_ci */
27262306a36Sopenharmony_cistatic bool loss_gilb_ell(struct netem_sched_data *q)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	struct clgstate *clg = &q->clg;
27562306a36Sopenharmony_ci	struct rnd_state *s = &q->prng.prng_state;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	switch (clg->state) {
27862306a36Sopenharmony_ci	case GOOD_STATE:
27962306a36Sopenharmony_ci		if (prandom_u32_state(s) < clg->a1)
28062306a36Sopenharmony_ci			clg->state = BAD_STATE;
28162306a36Sopenharmony_ci		if (prandom_u32_state(s) < clg->a4)
28262306a36Sopenharmony_ci			return true;
28362306a36Sopenharmony_ci		break;
28462306a36Sopenharmony_ci	case BAD_STATE:
28562306a36Sopenharmony_ci		if (prandom_u32_state(s) < clg->a2)
28662306a36Sopenharmony_ci			clg->state = GOOD_STATE;
28762306a36Sopenharmony_ci		if (prandom_u32_state(s) > clg->a3)
28862306a36Sopenharmony_ci			return true;
28962306a36Sopenharmony_ci	}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	return false;
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cistatic bool loss_event(struct netem_sched_data *q)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci	switch (q->loss_model) {
29762306a36Sopenharmony_ci	case CLG_RANDOM:
29862306a36Sopenharmony_ci		/* Random packet drop 0 => none, ~0 => all */
29962306a36Sopenharmony_ci		return q->loss && q->loss >= get_crandom(&q->loss_cor, &q->prng);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	case CLG_4_STATES:
30262306a36Sopenharmony_ci		/* 4state loss model algorithm (used also for GI model)
30362306a36Sopenharmony_ci		* Extracts a value from the markov 4 state loss generator,
30462306a36Sopenharmony_ci		* if it is 1 drops a packet and if needed writes the event in
30562306a36Sopenharmony_ci		* the kernel logs
30662306a36Sopenharmony_ci		*/
30762306a36Sopenharmony_ci		return loss_4state(q);
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	case CLG_GILB_ELL:
31062306a36Sopenharmony_ci		/* Gilbert-Elliot loss model algorithm
31162306a36Sopenharmony_ci		* Extracts a value from the Gilbert-Elliot loss generator,
31262306a36Sopenharmony_ci		* if it is 1 drops a packet and if needed writes the event in
31362306a36Sopenharmony_ci		* the kernel logs
31462306a36Sopenharmony_ci		*/
31562306a36Sopenharmony_ci		return loss_gilb_ell(q);
31662306a36Sopenharmony_ci	}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	return false;	/* not reached */
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci/* tabledist - return a pseudo-randomly distributed value with mean mu and
32362306a36Sopenharmony_ci * std deviation sigma.  Uses table lookup to approximate the desired
32462306a36Sopenharmony_ci * distribution, and a uniformly-distributed pseudo-random source.
32562306a36Sopenharmony_ci */
32662306a36Sopenharmony_cistatic s64 tabledist(s64 mu, s32 sigma,
32762306a36Sopenharmony_ci		     struct crndstate *state,
32862306a36Sopenharmony_ci		     struct prng *prng,
32962306a36Sopenharmony_ci		     const struct disttable *dist)
33062306a36Sopenharmony_ci{
33162306a36Sopenharmony_ci	s64 x;
33262306a36Sopenharmony_ci	long t;
33362306a36Sopenharmony_ci	u32 rnd;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	if (sigma == 0)
33662306a36Sopenharmony_ci		return mu;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	rnd = get_crandom(state, prng);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	/* default uniform distribution */
34162306a36Sopenharmony_ci	if (dist == NULL)
34262306a36Sopenharmony_ci		return ((rnd % (2 * (u32)sigma)) + mu) - sigma;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	t = dist->table[rnd % dist->size];
34562306a36Sopenharmony_ci	x = (sigma % NETEM_DIST_SCALE) * t;
34662306a36Sopenharmony_ci	if (x >= 0)
34762306a36Sopenharmony_ci		x += NETEM_DIST_SCALE/2;
34862306a36Sopenharmony_ci	else
34962306a36Sopenharmony_ci		x -= NETEM_DIST_SCALE/2;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	return  x / NETEM_DIST_SCALE + (sigma / NETEM_DIST_SCALE) * t + mu;
35262306a36Sopenharmony_ci}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_cistatic u64 packet_time_ns(u64 len, const struct netem_sched_data *q)
35562306a36Sopenharmony_ci{
35662306a36Sopenharmony_ci	len += q->packet_overhead;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	if (q->cell_size) {
35962306a36Sopenharmony_ci		u32 cells = reciprocal_divide(len, q->cell_size_reciprocal);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci		if (len > cells * q->cell_size)	/* extra cell needed for remainder */
36262306a36Sopenharmony_ci			cells++;
36362306a36Sopenharmony_ci		len = cells * (q->cell_size + q->cell_overhead);
36462306a36Sopenharmony_ci	}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	return div64_u64(len * NSEC_PER_SEC, q->rate);
36762306a36Sopenharmony_ci}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_cistatic void tfifo_reset(struct Qdisc *sch)
37062306a36Sopenharmony_ci{
37162306a36Sopenharmony_ci	struct netem_sched_data *q = qdisc_priv(sch);
37262306a36Sopenharmony_ci	struct rb_node *p = rb_first(&q->t_root);
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	while (p) {
37562306a36Sopenharmony_ci		struct sk_buff *skb = rb_to_skb(p);
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci		p = rb_next(p);
37862306a36Sopenharmony_ci		rb_erase(&skb->rbnode, &q->t_root);
37962306a36Sopenharmony_ci		rtnl_kfree_skbs(skb, skb);
38062306a36Sopenharmony_ci	}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	rtnl_kfree_skbs(q->t_head, q->t_tail);
38362306a36Sopenharmony_ci	q->t_head = NULL;
38462306a36Sopenharmony_ci	q->t_tail = NULL;
38562306a36Sopenharmony_ci}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_cistatic void tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	struct netem_sched_data *q = qdisc_priv(sch);
39062306a36Sopenharmony_ci	u64 tnext = netem_skb_cb(nskb)->time_to_send;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	if (!q->t_tail || tnext >= netem_skb_cb(q->t_tail)->time_to_send) {
39362306a36Sopenharmony_ci		if (q->t_tail)
39462306a36Sopenharmony_ci			q->t_tail->next = nskb;
39562306a36Sopenharmony_ci		else
39662306a36Sopenharmony_ci			q->t_head = nskb;
39762306a36Sopenharmony_ci		q->t_tail = nskb;
39862306a36Sopenharmony_ci	} else {
39962306a36Sopenharmony_ci		struct rb_node **p = &q->t_root.rb_node, *parent = NULL;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci		while (*p) {
40262306a36Sopenharmony_ci			struct sk_buff *skb;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci			parent = *p;
40562306a36Sopenharmony_ci			skb = rb_to_skb(parent);
40662306a36Sopenharmony_ci			if (tnext >= netem_skb_cb(skb)->time_to_send)
40762306a36Sopenharmony_ci				p = &parent->rb_right;
40862306a36Sopenharmony_ci			else
40962306a36Sopenharmony_ci				p = &parent->rb_left;
41062306a36Sopenharmony_ci		}
41162306a36Sopenharmony_ci		rb_link_node(&nskb->rbnode, parent, p);
41262306a36Sopenharmony_ci		rb_insert_color(&nskb->rbnode, &q->t_root);
41362306a36Sopenharmony_ci	}
41462306a36Sopenharmony_ci	sch->q.qlen++;
41562306a36Sopenharmony_ci}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci/* netem can't properly corrupt a megapacket (like we get from GSO), so instead
41862306a36Sopenharmony_ci * when we statistically choose to corrupt one, we instead segment it, returning
41962306a36Sopenharmony_ci * the first packet to be corrupted, and re-enqueue the remaining frames
42062306a36Sopenharmony_ci */
42162306a36Sopenharmony_cistatic struct sk_buff *netem_segment(struct sk_buff *skb, struct Qdisc *sch,
42262306a36Sopenharmony_ci				     struct sk_buff **to_free)
42362306a36Sopenharmony_ci{
42462306a36Sopenharmony_ci	struct sk_buff *segs;
42562306a36Sopenharmony_ci	netdev_features_t features = netif_skb_features(skb);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK);
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(segs)) {
43062306a36Sopenharmony_ci		qdisc_drop(skb, sch, to_free);
43162306a36Sopenharmony_ci		return NULL;
43262306a36Sopenharmony_ci	}
43362306a36Sopenharmony_ci	consume_skb(skb);
43462306a36Sopenharmony_ci	return segs;
43562306a36Sopenharmony_ci}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci/*
43862306a36Sopenharmony_ci * Insert one skb into qdisc.
43962306a36Sopenharmony_ci * Note: parent depends on return value to account for queue length.
44062306a36Sopenharmony_ci * 	NET_XMIT_DROP: queue length didn't change.
44162306a36Sopenharmony_ci *      NET_XMIT_SUCCESS: one skb was queued.
44262306a36Sopenharmony_ci */
44362306a36Sopenharmony_cistatic int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch,
44462306a36Sopenharmony_ci			 struct sk_buff **to_free)
44562306a36Sopenharmony_ci{
44662306a36Sopenharmony_ci	struct netem_sched_data *q = qdisc_priv(sch);
44762306a36Sopenharmony_ci	/* We don't fill cb now as skb_unshare() may invalidate it */
44862306a36Sopenharmony_ci	struct netem_skb_cb *cb;
44962306a36Sopenharmony_ci	struct sk_buff *skb2;
45062306a36Sopenharmony_ci	struct sk_buff *segs = NULL;
45162306a36Sopenharmony_ci	unsigned int prev_len = qdisc_pkt_len(skb);
45262306a36Sopenharmony_ci	int count = 1;
45362306a36Sopenharmony_ci	int rc = NET_XMIT_SUCCESS;
45462306a36Sopenharmony_ci	int rc_drop = NET_XMIT_DROP;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	/* Do not fool qdisc_drop_all() */
45762306a36Sopenharmony_ci	skb->prev = NULL;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	/* Random duplication */
46062306a36Sopenharmony_ci	if (q->duplicate && q->duplicate >= get_crandom(&q->dup_cor, &q->prng))
46162306a36Sopenharmony_ci		++count;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	/* Drop packet? */
46462306a36Sopenharmony_ci	if (loss_event(q)) {
46562306a36Sopenharmony_ci		if (q->ecn && INET_ECN_set_ce(skb))
46662306a36Sopenharmony_ci			qdisc_qstats_drop(sch); /* mark packet */
46762306a36Sopenharmony_ci		else
46862306a36Sopenharmony_ci			--count;
46962306a36Sopenharmony_ci	}
47062306a36Sopenharmony_ci	if (count == 0) {
47162306a36Sopenharmony_ci		qdisc_qstats_drop(sch);
47262306a36Sopenharmony_ci		__qdisc_drop(skb, to_free);
47362306a36Sopenharmony_ci		return NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
47462306a36Sopenharmony_ci	}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	/* If a delay is expected, orphan the skb. (orphaning usually takes
47762306a36Sopenharmony_ci	 * place at TX completion time, so _before_ the link transit delay)
47862306a36Sopenharmony_ci	 */
47962306a36Sopenharmony_ci	if (q->latency || q->jitter || q->rate)
48062306a36Sopenharmony_ci		skb_orphan_partial(skb);
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	/*
48362306a36Sopenharmony_ci	 * If we need to duplicate packet, then re-insert at top of the
48462306a36Sopenharmony_ci	 * qdisc tree, since parent queuer expects that only one
48562306a36Sopenharmony_ci	 * skb will be queued.
48662306a36Sopenharmony_ci	 */
48762306a36Sopenharmony_ci	if (count > 1 && (skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) {
48862306a36Sopenharmony_ci		struct Qdisc *rootq = qdisc_root_bh(sch);
48962306a36Sopenharmony_ci		u32 dupsave = q->duplicate; /* prevent duplicating a dup... */
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci		q->duplicate = 0;
49262306a36Sopenharmony_ci		rootq->enqueue(skb2, rootq, to_free);
49362306a36Sopenharmony_ci		q->duplicate = dupsave;
49462306a36Sopenharmony_ci		rc_drop = NET_XMIT_SUCCESS;
49562306a36Sopenharmony_ci	}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	/*
49862306a36Sopenharmony_ci	 * Randomized packet corruption.
49962306a36Sopenharmony_ci	 * Make copy if needed since we are modifying
50062306a36Sopenharmony_ci	 * If packet is going to be hardware checksummed, then
50162306a36Sopenharmony_ci	 * do it now in software before we mangle it.
50262306a36Sopenharmony_ci	 */
50362306a36Sopenharmony_ci	if (q->corrupt && q->corrupt >= get_crandom(&q->corrupt_cor, &q->prng)) {
50462306a36Sopenharmony_ci		if (skb_is_gso(skb)) {
50562306a36Sopenharmony_ci			skb = netem_segment(skb, sch, to_free);
50662306a36Sopenharmony_ci			if (!skb)
50762306a36Sopenharmony_ci				return rc_drop;
50862306a36Sopenharmony_ci			segs = skb->next;
50962306a36Sopenharmony_ci			skb_mark_not_on_list(skb);
51062306a36Sopenharmony_ci			qdisc_skb_cb(skb)->pkt_len = skb->len;
51162306a36Sopenharmony_ci		}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci		skb = skb_unshare(skb, GFP_ATOMIC);
51462306a36Sopenharmony_ci		if (unlikely(!skb)) {
51562306a36Sopenharmony_ci			qdisc_qstats_drop(sch);
51662306a36Sopenharmony_ci			goto finish_segs;
51762306a36Sopenharmony_ci		}
51862306a36Sopenharmony_ci		if (skb->ip_summed == CHECKSUM_PARTIAL &&
51962306a36Sopenharmony_ci		    skb_checksum_help(skb)) {
52062306a36Sopenharmony_ci			qdisc_drop(skb, sch, to_free);
52162306a36Sopenharmony_ci			skb = NULL;
52262306a36Sopenharmony_ci			goto finish_segs;
52362306a36Sopenharmony_ci		}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci		skb->data[get_random_u32_below(skb_headlen(skb))] ^=
52662306a36Sopenharmony_ci			1<<get_random_u32_below(8);
52762306a36Sopenharmony_ci	}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	if (unlikely(sch->q.qlen >= sch->limit)) {
53062306a36Sopenharmony_ci		/* re-link segs, so that qdisc_drop_all() frees them all */
53162306a36Sopenharmony_ci		skb->next = segs;
53262306a36Sopenharmony_ci		qdisc_drop_all(skb, sch, to_free);
53362306a36Sopenharmony_ci		return rc_drop;
53462306a36Sopenharmony_ci	}
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	qdisc_qstats_backlog_inc(sch, skb);
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	cb = netem_skb_cb(skb);
53962306a36Sopenharmony_ci	if (q->gap == 0 ||		/* not doing reordering */
54062306a36Sopenharmony_ci	    q->counter < q->gap - 1 ||	/* inside last reordering gap */
54162306a36Sopenharmony_ci	    q->reorder < get_crandom(&q->reorder_cor, &q->prng)) {
54262306a36Sopenharmony_ci		u64 now;
54362306a36Sopenharmony_ci		s64 delay;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci		delay = tabledist(q->latency, q->jitter,
54662306a36Sopenharmony_ci				  &q->delay_cor, &q->prng, q->delay_dist);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci		now = ktime_get_ns();
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci		if (q->rate) {
55162306a36Sopenharmony_ci			struct netem_skb_cb *last = NULL;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci			if (sch->q.tail)
55462306a36Sopenharmony_ci				last = netem_skb_cb(sch->q.tail);
55562306a36Sopenharmony_ci			if (q->t_root.rb_node) {
55662306a36Sopenharmony_ci				struct sk_buff *t_skb;
55762306a36Sopenharmony_ci				struct netem_skb_cb *t_last;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci				t_skb = skb_rb_last(&q->t_root);
56062306a36Sopenharmony_ci				t_last = netem_skb_cb(t_skb);
56162306a36Sopenharmony_ci				if (!last ||
56262306a36Sopenharmony_ci				    t_last->time_to_send > last->time_to_send)
56362306a36Sopenharmony_ci					last = t_last;
56462306a36Sopenharmony_ci			}
56562306a36Sopenharmony_ci			if (q->t_tail) {
56662306a36Sopenharmony_ci				struct netem_skb_cb *t_last =
56762306a36Sopenharmony_ci					netem_skb_cb(q->t_tail);
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci				if (!last ||
57062306a36Sopenharmony_ci				    t_last->time_to_send > last->time_to_send)
57162306a36Sopenharmony_ci					last = t_last;
57262306a36Sopenharmony_ci			}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci			if (last) {
57562306a36Sopenharmony_ci				/*
57662306a36Sopenharmony_ci				 * Last packet in queue is reference point (now),
57762306a36Sopenharmony_ci				 * calculate this time bonus and subtract
57862306a36Sopenharmony_ci				 * from delay.
57962306a36Sopenharmony_ci				 */
58062306a36Sopenharmony_ci				delay -= last->time_to_send - now;
58162306a36Sopenharmony_ci				delay = max_t(s64, 0, delay);
58262306a36Sopenharmony_ci				now = last->time_to_send;
58362306a36Sopenharmony_ci			}
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci			delay += packet_time_ns(qdisc_pkt_len(skb), q);
58662306a36Sopenharmony_ci		}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci		cb->time_to_send = now + delay;
58962306a36Sopenharmony_ci		++q->counter;
59062306a36Sopenharmony_ci		tfifo_enqueue(skb, sch);
59162306a36Sopenharmony_ci	} else {
59262306a36Sopenharmony_ci		/*
59362306a36Sopenharmony_ci		 * Do re-ordering by putting one out of N packets at the front
59462306a36Sopenharmony_ci		 * of the queue.
59562306a36Sopenharmony_ci		 */
59662306a36Sopenharmony_ci		cb->time_to_send = ktime_get_ns();
59762306a36Sopenharmony_ci		q->counter = 0;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci		__qdisc_enqueue_head(skb, &sch->q);
60062306a36Sopenharmony_ci		sch->qstats.requeues++;
60162306a36Sopenharmony_ci	}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_cifinish_segs:
60462306a36Sopenharmony_ci	if (segs) {
60562306a36Sopenharmony_ci		unsigned int len, last_len;
60662306a36Sopenharmony_ci		int nb;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci		len = skb ? skb->len : 0;
60962306a36Sopenharmony_ci		nb = skb ? 1 : 0;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci		while (segs) {
61262306a36Sopenharmony_ci			skb2 = segs->next;
61362306a36Sopenharmony_ci			skb_mark_not_on_list(segs);
61462306a36Sopenharmony_ci			qdisc_skb_cb(segs)->pkt_len = segs->len;
61562306a36Sopenharmony_ci			last_len = segs->len;
61662306a36Sopenharmony_ci			rc = qdisc_enqueue(segs, sch, to_free);
61762306a36Sopenharmony_ci			if (rc != NET_XMIT_SUCCESS) {
61862306a36Sopenharmony_ci				if (net_xmit_drop_count(rc))
61962306a36Sopenharmony_ci					qdisc_qstats_drop(sch);
62062306a36Sopenharmony_ci			} else {
62162306a36Sopenharmony_ci				nb++;
62262306a36Sopenharmony_ci				len += last_len;
62362306a36Sopenharmony_ci			}
62462306a36Sopenharmony_ci			segs = skb2;
62562306a36Sopenharmony_ci		}
62662306a36Sopenharmony_ci		/* Parent qdiscs accounted for 1 skb of size @prev_len */
62762306a36Sopenharmony_ci		qdisc_tree_reduce_backlog(sch, -(nb - 1), -(len - prev_len));
62862306a36Sopenharmony_ci	} else if (!skb) {
62962306a36Sopenharmony_ci		return NET_XMIT_DROP;
63062306a36Sopenharmony_ci	}
63162306a36Sopenharmony_ci	return NET_XMIT_SUCCESS;
63262306a36Sopenharmony_ci}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci/* Delay the next round with a new future slot with a
63562306a36Sopenharmony_ci * correct number of bytes and packets.
63662306a36Sopenharmony_ci */
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_cistatic void get_slot_next(struct netem_sched_data *q, u64 now)
63962306a36Sopenharmony_ci{
64062306a36Sopenharmony_ci	s64 next_delay;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	if (!q->slot_dist)
64362306a36Sopenharmony_ci		next_delay = q->slot_config.min_delay +
64462306a36Sopenharmony_ci				(get_random_u32() *
64562306a36Sopenharmony_ci				 (q->slot_config.max_delay -
64662306a36Sopenharmony_ci				  q->slot_config.min_delay) >> 32);
64762306a36Sopenharmony_ci	else
64862306a36Sopenharmony_ci		next_delay = tabledist(q->slot_config.dist_delay,
64962306a36Sopenharmony_ci				       (s32)(q->slot_config.dist_jitter),
65062306a36Sopenharmony_ci				       NULL, &q->prng, q->slot_dist);
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	q->slot.slot_next = now + next_delay;
65362306a36Sopenharmony_ci	q->slot.packets_left = q->slot_config.max_packets;
65462306a36Sopenharmony_ci	q->slot.bytes_left = q->slot_config.max_bytes;
65562306a36Sopenharmony_ci}
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_cistatic struct sk_buff *netem_peek(struct netem_sched_data *q)
65862306a36Sopenharmony_ci{
65962306a36Sopenharmony_ci	struct sk_buff *skb = skb_rb_first(&q->t_root);
66062306a36Sopenharmony_ci	u64 t1, t2;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	if (!skb)
66362306a36Sopenharmony_ci		return q->t_head;
66462306a36Sopenharmony_ci	if (!q->t_head)
66562306a36Sopenharmony_ci		return skb;
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	t1 = netem_skb_cb(skb)->time_to_send;
66862306a36Sopenharmony_ci	t2 = netem_skb_cb(q->t_head)->time_to_send;
66962306a36Sopenharmony_ci	if (t1 < t2)
67062306a36Sopenharmony_ci		return skb;
67162306a36Sopenharmony_ci	return q->t_head;
67262306a36Sopenharmony_ci}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_cistatic void netem_erase_head(struct netem_sched_data *q, struct sk_buff *skb)
67562306a36Sopenharmony_ci{
67662306a36Sopenharmony_ci	if (skb == q->t_head) {
67762306a36Sopenharmony_ci		q->t_head = skb->next;
67862306a36Sopenharmony_ci		if (!q->t_head)
67962306a36Sopenharmony_ci			q->t_tail = NULL;
68062306a36Sopenharmony_ci	} else {
68162306a36Sopenharmony_ci		rb_erase(&skb->rbnode, &q->t_root);
68262306a36Sopenharmony_ci	}
68362306a36Sopenharmony_ci}
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_cistatic struct sk_buff *netem_dequeue(struct Qdisc *sch)
68662306a36Sopenharmony_ci{
68762306a36Sopenharmony_ci	struct netem_sched_data *q = qdisc_priv(sch);
68862306a36Sopenharmony_ci	struct sk_buff *skb;
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_citfifo_dequeue:
69162306a36Sopenharmony_ci	skb = __qdisc_dequeue_head(&sch->q);
69262306a36Sopenharmony_ci	if (skb) {
69362306a36Sopenharmony_ci		qdisc_qstats_backlog_dec(sch, skb);
69462306a36Sopenharmony_cideliver:
69562306a36Sopenharmony_ci		qdisc_bstats_update(sch, skb);
69662306a36Sopenharmony_ci		return skb;
69762306a36Sopenharmony_ci	}
69862306a36Sopenharmony_ci	skb = netem_peek(q);
69962306a36Sopenharmony_ci	if (skb) {
70062306a36Sopenharmony_ci		u64 time_to_send;
70162306a36Sopenharmony_ci		u64 now = ktime_get_ns();
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci		/* if more time remaining? */
70462306a36Sopenharmony_ci		time_to_send = netem_skb_cb(skb)->time_to_send;
70562306a36Sopenharmony_ci		if (q->slot.slot_next && q->slot.slot_next < time_to_send)
70662306a36Sopenharmony_ci			get_slot_next(q, now);
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci		if (time_to_send <= now && q->slot.slot_next <= now) {
70962306a36Sopenharmony_ci			netem_erase_head(q, skb);
71062306a36Sopenharmony_ci			sch->q.qlen--;
71162306a36Sopenharmony_ci			qdisc_qstats_backlog_dec(sch, skb);
71262306a36Sopenharmony_ci			skb->next = NULL;
71362306a36Sopenharmony_ci			skb->prev = NULL;
71462306a36Sopenharmony_ci			/* skb->dev shares skb->rbnode area,
71562306a36Sopenharmony_ci			 * we need to restore its value.
71662306a36Sopenharmony_ci			 */
71762306a36Sopenharmony_ci			skb->dev = qdisc_dev(sch);
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci			if (q->slot.slot_next) {
72062306a36Sopenharmony_ci				q->slot.packets_left--;
72162306a36Sopenharmony_ci				q->slot.bytes_left -= qdisc_pkt_len(skb);
72262306a36Sopenharmony_ci				if (q->slot.packets_left <= 0 ||
72362306a36Sopenharmony_ci				    q->slot.bytes_left <= 0)
72462306a36Sopenharmony_ci					get_slot_next(q, now);
72562306a36Sopenharmony_ci			}
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci			if (q->qdisc) {
72862306a36Sopenharmony_ci				unsigned int pkt_len = qdisc_pkt_len(skb);
72962306a36Sopenharmony_ci				struct sk_buff *to_free = NULL;
73062306a36Sopenharmony_ci				int err;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci				err = qdisc_enqueue(skb, q->qdisc, &to_free);
73362306a36Sopenharmony_ci				kfree_skb_list(to_free);
73462306a36Sopenharmony_ci				if (err != NET_XMIT_SUCCESS &&
73562306a36Sopenharmony_ci				    net_xmit_drop_count(err)) {
73662306a36Sopenharmony_ci					qdisc_qstats_drop(sch);
73762306a36Sopenharmony_ci					qdisc_tree_reduce_backlog(sch, 1,
73862306a36Sopenharmony_ci								  pkt_len);
73962306a36Sopenharmony_ci				}
74062306a36Sopenharmony_ci				goto tfifo_dequeue;
74162306a36Sopenharmony_ci			}
74262306a36Sopenharmony_ci			goto deliver;
74362306a36Sopenharmony_ci		}
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci		if (q->qdisc) {
74662306a36Sopenharmony_ci			skb = q->qdisc->ops->dequeue(q->qdisc);
74762306a36Sopenharmony_ci			if (skb)
74862306a36Sopenharmony_ci				goto deliver;
74962306a36Sopenharmony_ci		}
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci		qdisc_watchdog_schedule_ns(&q->watchdog,
75262306a36Sopenharmony_ci					   max(time_to_send,
75362306a36Sopenharmony_ci					       q->slot.slot_next));
75462306a36Sopenharmony_ci	}
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	if (q->qdisc) {
75762306a36Sopenharmony_ci		skb = q->qdisc->ops->dequeue(q->qdisc);
75862306a36Sopenharmony_ci		if (skb)
75962306a36Sopenharmony_ci			goto deliver;
76062306a36Sopenharmony_ci	}
76162306a36Sopenharmony_ci	return NULL;
76262306a36Sopenharmony_ci}
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_cistatic void netem_reset(struct Qdisc *sch)
76562306a36Sopenharmony_ci{
76662306a36Sopenharmony_ci	struct netem_sched_data *q = qdisc_priv(sch);
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	qdisc_reset_queue(sch);
76962306a36Sopenharmony_ci	tfifo_reset(sch);
77062306a36Sopenharmony_ci	if (q->qdisc)
77162306a36Sopenharmony_ci		qdisc_reset(q->qdisc);
77262306a36Sopenharmony_ci	qdisc_watchdog_cancel(&q->watchdog);
77362306a36Sopenharmony_ci}
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_cistatic void dist_free(struct disttable *d)
77662306a36Sopenharmony_ci{
77762306a36Sopenharmony_ci	kvfree(d);
77862306a36Sopenharmony_ci}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci/*
78162306a36Sopenharmony_ci * Distribution data is a variable size payload containing
78262306a36Sopenharmony_ci * signed 16 bit values.
78362306a36Sopenharmony_ci */
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_cistatic int get_dist_table(struct disttable **tbl, const struct nlattr *attr)
78662306a36Sopenharmony_ci{
78762306a36Sopenharmony_ci	size_t n = nla_len(attr)/sizeof(__s16);
78862306a36Sopenharmony_ci	const __s16 *data = nla_data(attr);
78962306a36Sopenharmony_ci	struct disttable *d;
79062306a36Sopenharmony_ci	int i;
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	if (!n || n > NETEM_DIST_MAX)
79362306a36Sopenharmony_ci		return -EINVAL;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	d = kvmalloc(struct_size(d, table, n), GFP_KERNEL);
79662306a36Sopenharmony_ci	if (!d)
79762306a36Sopenharmony_ci		return -ENOMEM;
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	d->size = n;
80062306a36Sopenharmony_ci	for (i = 0; i < n; i++)
80162306a36Sopenharmony_ci		d->table[i] = data[i];
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	*tbl = d;
80462306a36Sopenharmony_ci	return 0;
80562306a36Sopenharmony_ci}
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_cistatic void get_slot(struct netem_sched_data *q, const struct nlattr *attr)
80862306a36Sopenharmony_ci{
80962306a36Sopenharmony_ci	const struct tc_netem_slot *c = nla_data(attr);
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	q->slot_config = *c;
81262306a36Sopenharmony_ci	if (q->slot_config.max_packets == 0)
81362306a36Sopenharmony_ci		q->slot_config.max_packets = INT_MAX;
81462306a36Sopenharmony_ci	if (q->slot_config.max_bytes == 0)
81562306a36Sopenharmony_ci		q->slot_config.max_bytes = INT_MAX;
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	/* capping dist_jitter to the range acceptable by tabledist() */
81862306a36Sopenharmony_ci	q->slot_config.dist_jitter = min_t(__s64, INT_MAX, abs(q->slot_config.dist_jitter));
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	q->slot.packets_left = q->slot_config.max_packets;
82162306a36Sopenharmony_ci	q->slot.bytes_left = q->slot_config.max_bytes;
82262306a36Sopenharmony_ci	if (q->slot_config.min_delay | q->slot_config.max_delay |
82362306a36Sopenharmony_ci	    q->slot_config.dist_jitter)
82462306a36Sopenharmony_ci		q->slot.slot_next = ktime_get_ns();
82562306a36Sopenharmony_ci	else
82662306a36Sopenharmony_ci		q->slot.slot_next = 0;
82762306a36Sopenharmony_ci}
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_cistatic void get_correlation(struct netem_sched_data *q, const struct nlattr *attr)
83062306a36Sopenharmony_ci{
83162306a36Sopenharmony_ci	const struct tc_netem_corr *c = nla_data(attr);
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	init_crandom(&q->delay_cor, c->delay_corr);
83462306a36Sopenharmony_ci	init_crandom(&q->loss_cor, c->loss_corr);
83562306a36Sopenharmony_ci	init_crandom(&q->dup_cor, c->dup_corr);
83662306a36Sopenharmony_ci}
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_cistatic void get_reorder(struct netem_sched_data *q, const struct nlattr *attr)
83962306a36Sopenharmony_ci{
84062306a36Sopenharmony_ci	const struct tc_netem_reorder *r = nla_data(attr);
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	q->reorder = r->probability;
84362306a36Sopenharmony_ci	init_crandom(&q->reorder_cor, r->correlation);
84462306a36Sopenharmony_ci}
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_cistatic void get_corrupt(struct netem_sched_data *q, const struct nlattr *attr)
84762306a36Sopenharmony_ci{
84862306a36Sopenharmony_ci	const struct tc_netem_corrupt *r = nla_data(attr);
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	q->corrupt = r->probability;
85162306a36Sopenharmony_ci	init_crandom(&q->corrupt_cor, r->correlation);
85262306a36Sopenharmony_ci}
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_cistatic void get_rate(struct netem_sched_data *q, const struct nlattr *attr)
85562306a36Sopenharmony_ci{
85662306a36Sopenharmony_ci	const struct tc_netem_rate *r = nla_data(attr);
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	q->rate = r->rate;
85962306a36Sopenharmony_ci	q->packet_overhead = r->packet_overhead;
86062306a36Sopenharmony_ci	q->cell_size = r->cell_size;
86162306a36Sopenharmony_ci	q->cell_overhead = r->cell_overhead;
86262306a36Sopenharmony_ci	if (q->cell_size)
86362306a36Sopenharmony_ci		q->cell_size_reciprocal = reciprocal_value(q->cell_size);
86462306a36Sopenharmony_ci	else
86562306a36Sopenharmony_ci		q->cell_size_reciprocal = (struct reciprocal_value) { 0 };
86662306a36Sopenharmony_ci}
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_cistatic int get_loss_clg(struct netem_sched_data *q, const struct nlattr *attr)
86962306a36Sopenharmony_ci{
87062306a36Sopenharmony_ci	const struct nlattr *la;
87162306a36Sopenharmony_ci	int rem;
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	nla_for_each_nested(la, attr, rem) {
87462306a36Sopenharmony_ci		u16 type = nla_type(la);
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci		switch (type) {
87762306a36Sopenharmony_ci		case NETEM_LOSS_GI: {
87862306a36Sopenharmony_ci			const struct tc_netem_gimodel *gi = nla_data(la);
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci			if (nla_len(la) < sizeof(struct tc_netem_gimodel)) {
88162306a36Sopenharmony_ci				pr_info("netem: incorrect gi model size\n");
88262306a36Sopenharmony_ci				return -EINVAL;
88362306a36Sopenharmony_ci			}
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci			q->loss_model = CLG_4_STATES;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci			q->clg.state = TX_IN_GAP_PERIOD;
88862306a36Sopenharmony_ci			q->clg.a1 = gi->p13;
88962306a36Sopenharmony_ci			q->clg.a2 = gi->p31;
89062306a36Sopenharmony_ci			q->clg.a3 = gi->p32;
89162306a36Sopenharmony_ci			q->clg.a4 = gi->p14;
89262306a36Sopenharmony_ci			q->clg.a5 = gi->p23;
89362306a36Sopenharmony_ci			break;
89462306a36Sopenharmony_ci		}
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci		case NETEM_LOSS_GE: {
89762306a36Sopenharmony_ci			const struct tc_netem_gemodel *ge = nla_data(la);
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci			if (nla_len(la) < sizeof(struct tc_netem_gemodel)) {
90062306a36Sopenharmony_ci				pr_info("netem: incorrect ge model size\n");
90162306a36Sopenharmony_ci				return -EINVAL;
90262306a36Sopenharmony_ci			}
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci			q->loss_model = CLG_GILB_ELL;
90562306a36Sopenharmony_ci			q->clg.state = GOOD_STATE;
90662306a36Sopenharmony_ci			q->clg.a1 = ge->p;
90762306a36Sopenharmony_ci			q->clg.a2 = ge->r;
90862306a36Sopenharmony_ci			q->clg.a3 = ge->h;
90962306a36Sopenharmony_ci			q->clg.a4 = ge->k1;
91062306a36Sopenharmony_ci			break;
91162306a36Sopenharmony_ci		}
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci		default:
91462306a36Sopenharmony_ci			pr_info("netem: unknown loss type %u\n", type);
91562306a36Sopenharmony_ci			return -EINVAL;
91662306a36Sopenharmony_ci		}
91762306a36Sopenharmony_ci	}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	return 0;
92062306a36Sopenharmony_ci}
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_cistatic const struct nla_policy netem_policy[TCA_NETEM_MAX + 1] = {
92362306a36Sopenharmony_ci	[TCA_NETEM_CORR]	= { .len = sizeof(struct tc_netem_corr) },
92462306a36Sopenharmony_ci	[TCA_NETEM_REORDER]	= { .len = sizeof(struct tc_netem_reorder) },
92562306a36Sopenharmony_ci	[TCA_NETEM_CORRUPT]	= { .len = sizeof(struct tc_netem_corrupt) },
92662306a36Sopenharmony_ci	[TCA_NETEM_RATE]	= { .len = sizeof(struct tc_netem_rate) },
92762306a36Sopenharmony_ci	[TCA_NETEM_LOSS]	= { .type = NLA_NESTED },
92862306a36Sopenharmony_ci	[TCA_NETEM_ECN]		= { .type = NLA_U32 },
92962306a36Sopenharmony_ci	[TCA_NETEM_RATE64]	= { .type = NLA_U64 },
93062306a36Sopenharmony_ci	[TCA_NETEM_LATENCY64]	= { .type = NLA_S64 },
93162306a36Sopenharmony_ci	[TCA_NETEM_JITTER64]	= { .type = NLA_S64 },
93262306a36Sopenharmony_ci	[TCA_NETEM_SLOT]	= { .len = sizeof(struct tc_netem_slot) },
93362306a36Sopenharmony_ci	[TCA_NETEM_PRNG_SEED]	= { .type = NLA_U64 },
93462306a36Sopenharmony_ci};
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_cistatic int parse_attr(struct nlattr *tb[], int maxtype, struct nlattr *nla,
93762306a36Sopenharmony_ci		      const struct nla_policy *policy, int len)
93862306a36Sopenharmony_ci{
93962306a36Sopenharmony_ci	int nested_len = nla_len(nla) - NLA_ALIGN(len);
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	if (nested_len < 0) {
94262306a36Sopenharmony_ci		pr_info("netem: invalid attributes len %d\n", nested_len);
94362306a36Sopenharmony_ci		return -EINVAL;
94462306a36Sopenharmony_ci	}
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	if (nested_len >= nla_attr_size(0))
94762306a36Sopenharmony_ci		return nla_parse_deprecated(tb, maxtype,
94862306a36Sopenharmony_ci					    nla_data(nla) + NLA_ALIGN(len),
94962306a36Sopenharmony_ci					    nested_len, policy, NULL);
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
95262306a36Sopenharmony_ci	return 0;
95362306a36Sopenharmony_ci}
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci/* Parse netlink message to set options */
95662306a36Sopenharmony_cistatic int netem_change(struct Qdisc *sch, struct nlattr *opt,
95762306a36Sopenharmony_ci			struct netlink_ext_ack *extack)
95862306a36Sopenharmony_ci{
95962306a36Sopenharmony_ci	struct netem_sched_data *q = qdisc_priv(sch);
96062306a36Sopenharmony_ci	struct nlattr *tb[TCA_NETEM_MAX + 1];
96162306a36Sopenharmony_ci	struct disttable *delay_dist = NULL;
96262306a36Sopenharmony_ci	struct disttable *slot_dist = NULL;
96362306a36Sopenharmony_ci	struct tc_netem_qopt *qopt;
96462306a36Sopenharmony_ci	struct clgstate old_clg;
96562306a36Sopenharmony_ci	int old_loss_model = CLG_RANDOM;
96662306a36Sopenharmony_ci	int ret;
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	qopt = nla_data(opt);
96962306a36Sopenharmony_ci	ret = parse_attr(tb, TCA_NETEM_MAX, opt, netem_policy, sizeof(*qopt));
97062306a36Sopenharmony_ci	if (ret < 0)
97162306a36Sopenharmony_ci		return ret;
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	if (tb[TCA_NETEM_DELAY_DIST]) {
97462306a36Sopenharmony_ci		ret = get_dist_table(&delay_dist, tb[TCA_NETEM_DELAY_DIST]);
97562306a36Sopenharmony_ci		if (ret)
97662306a36Sopenharmony_ci			goto table_free;
97762306a36Sopenharmony_ci	}
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	if (tb[TCA_NETEM_SLOT_DIST]) {
98062306a36Sopenharmony_ci		ret = get_dist_table(&slot_dist, tb[TCA_NETEM_SLOT_DIST]);
98162306a36Sopenharmony_ci		if (ret)
98262306a36Sopenharmony_ci			goto table_free;
98362306a36Sopenharmony_ci	}
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	sch_tree_lock(sch);
98662306a36Sopenharmony_ci	/* backup q->clg and q->loss_model */
98762306a36Sopenharmony_ci	old_clg = q->clg;
98862306a36Sopenharmony_ci	old_loss_model = q->loss_model;
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	if (tb[TCA_NETEM_LOSS]) {
99162306a36Sopenharmony_ci		ret = get_loss_clg(q, tb[TCA_NETEM_LOSS]);
99262306a36Sopenharmony_ci		if (ret) {
99362306a36Sopenharmony_ci			q->loss_model = old_loss_model;
99462306a36Sopenharmony_ci			q->clg = old_clg;
99562306a36Sopenharmony_ci			goto unlock;
99662306a36Sopenharmony_ci		}
99762306a36Sopenharmony_ci	} else {
99862306a36Sopenharmony_ci		q->loss_model = CLG_RANDOM;
99962306a36Sopenharmony_ci	}
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	if (delay_dist)
100262306a36Sopenharmony_ci		swap(q->delay_dist, delay_dist);
100362306a36Sopenharmony_ci	if (slot_dist)
100462306a36Sopenharmony_ci		swap(q->slot_dist, slot_dist);
100562306a36Sopenharmony_ci	sch->limit = qopt->limit;
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	q->latency = PSCHED_TICKS2NS(qopt->latency);
100862306a36Sopenharmony_ci	q->jitter = PSCHED_TICKS2NS(qopt->jitter);
100962306a36Sopenharmony_ci	q->limit = qopt->limit;
101062306a36Sopenharmony_ci	q->gap = qopt->gap;
101162306a36Sopenharmony_ci	q->counter = 0;
101262306a36Sopenharmony_ci	q->loss = qopt->loss;
101362306a36Sopenharmony_ci	q->duplicate = qopt->duplicate;
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	/* for compatibility with earlier versions.
101662306a36Sopenharmony_ci	 * if gap is set, need to assume 100% probability
101762306a36Sopenharmony_ci	 */
101862306a36Sopenharmony_ci	if (q->gap)
101962306a36Sopenharmony_ci		q->reorder = ~0;
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	if (tb[TCA_NETEM_CORR])
102262306a36Sopenharmony_ci		get_correlation(q, tb[TCA_NETEM_CORR]);
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	if (tb[TCA_NETEM_REORDER])
102562306a36Sopenharmony_ci		get_reorder(q, tb[TCA_NETEM_REORDER]);
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	if (tb[TCA_NETEM_CORRUPT])
102862306a36Sopenharmony_ci		get_corrupt(q, tb[TCA_NETEM_CORRUPT]);
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	if (tb[TCA_NETEM_RATE])
103162306a36Sopenharmony_ci		get_rate(q, tb[TCA_NETEM_RATE]);
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	if (tb[TCA_NETEM_RATE64])
103462306a36Sopenharmony_ci		q->rate = max_t(u64, q->rate,
103562306a36Sopenharmony_ci				nla_get_u64(tb[TCA_NETEM_RATE64]));
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	if (tb[TCA_NETEM_LATENCY64])
103862306a36Sopenharmony_ci		q->latency = nla_get_s64(tb[TCA_NETEM_LATENCY64]);
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci	if (tb[TCA_NETEM_JITTER64])
104162306a36Sopenharmony_ci		q->jitter = nla_get_s64(tb[TCA_NETEM_JITTER64]);
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	if (tb[TCA_NETEM_ECN])
104462306a36Sopenharmony_ci		q->ecn = nla_get_u32(tb[TCA_NETEM_ECN]);
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	if (tb[TCA_NETEM_SLOT])
104762306a36Sopenharmony_ci		get_slot(q, tb[TCA_NETEM_SLOT]);
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci	/* capping jitter to the range acceptable by tabledist() */
105062306a36Sopenharmony_ci	q->jitter = min_t(s64, abs(q->jitter), INT_MAX);
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	if (tb[TCA_NETEM_PRNG_SEED])
105362306a36Sopenharmony_ci		q->prng.seed = nla_get_u64(tb[TCA_NETEM_PRNG_SEED]);
105462306a36Sopenharmony_ci	else
105562306a36Sopenharmony_ci		q->prng.seed = get_random_u64();
105662306a36Sopenharmony_ci	prandom_seed_state(&q->prng.prng_state, q->prng.seed);
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ciunlock:
105962306a36Sopenharmony_ci	sch_tree_unlock(sch);
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_citable_free:
106262306a36Sopenharmony_ci	dist_free(delay_dist);
106362306a36Sopenharmony_ci	dist_free(slot_dist);
106462306a36Sopenharmony_ci	return ret;
106562306a36Sopenharmony_ci}
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_cistatic int netem_init(struct Qdisc *sch, struct nlattr *opt,
106862306a36Sopenharmony_ci		      struct netlink_ext_ack *extack)
106962306a36Sopenharmony_ci{
107062306a36Sopenharmony_ci	struct netem_sched_data *q = qdisc_priv(sch);
107162306a36Sopenharmony_ci	int ret;
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	qdisc_watchdog_init(&q->watchdog, sch);
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	if (!opt)
107662306a36Sopenharmony_ci		return -EINVAL;
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	q->loss_model = CLG_RANDOM;
107962306a36Sopenharmony_ci	ret = netem_change(sch, opt, extack);
108062306a36Sopenharmony_ci	if (ret)
108162306a36Sopenharmony_ci		pr_info("netem: change failed\n");
108262306a36Sopenharmony_ci	return ret;
108362306a36Sopenharmony_ci}
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_cistatic void netem_destroy(struct Qdisc *sch)
108662306a36Sopenharmony_ci{
108762306a36Sopenharmony_ci	struct netem_sched_data *q = qdisc_priv(sch);
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	qdisc_watchdog_cancel(&q->watchdog);
109062306a36Sopenharmony_ci	if (q->qdisc)
109162306a36Sopenharmony_ci		qdisc_put(q->qdisc);
109262306a36Sopenharmony_ci	dist_free(q->delay_dist);
109362306a36Sopenharmony_ci	dist_free(q->slot_dist);
109462306a36Sopenharmony_ci}
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_cistatic int dump_loss_model(const struct netem_sched_data *q,
109762306a36Sopenharmony_ci			   struct sk_buff *skb)
109862306a36Sopenharmony_ci{
109962306a36Sopenharmony_ci	struct nlattr *nest;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	nest = nla_nest_start_noflag(skb, TCA_NETEM_LOSS);
110262306a36Sopenharmony_ci	if (nest == NULL)
110362306a36Sopenharmony_ci		goto nla_put_failure;
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	switch (q->loss_model) {
110662306a36Sopenharmony_ci	case CLG_RANDOM:
110762306a36Sopenharmony_ci		/* legacy loss model */
110862306a36Sopenharmony_ci		nla_nest_cancel(skb, nest);
110962306a36Sopenharmony_ci		return 0;	/* no data */
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	case CLG_4_STATES: {
111262306a36Sopenharmony_ci		struct tc_netem_gimodel gi = {
111362306a36Sopenharmony_ci			.p13 = q->clg.a1,
111462306a36Sopenharmony_ci			.p31 = q->clg.a2,
111562306a36Sopenharmony_ci			.p32 = q->clg.a3,
111662306a36Sopenharmony_ci			.p14 = q->clg.a4,
111762306a36Sopenharmony_ci			.p23 = q->clg.a5,
111862306a36Sopenharmony_ci		};
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci		if (nla_put(skb, NETEM_LOSS_GI, sizeof(gi), &gi))
112162306a36Sopenharmony_ci			goto nla_put_failure;
112262306a36Sopenharmony_ci		break;
112362306a36Sopenharmony_ci	}
112462306a36Sopenharmony_ci	case CLG_GILB_ELL: {
112562306a36Sopenharmony_ci		struct tc_netem_gemodel ge = {
112662306a36Sopenharmony_ci			.p = q->clg.a1,
112762306a36Sopenharmony_ci			.r = q->clg.a2,
112862306a36Sopenharmony_ci			.h = q->clg.a3,
112962306a36Sopenharmony_ci			.k1 = q->clg.a4,
113062306a36Sopenharmony_ci		};
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci		if (nla_put(skb, NETEM_LOSS_GE, sizeof(ge), &ge))
113362306a36Sopenharmony_ci			goto nla_put_failure;
113462306a36Sopenharmony_ci		break;
113562306a36Sopenharmony_ci	}
113662306a36Sopenharmony_ci	}
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	nla_nest_end(skb, nest);
113962306a36Sopenharmony_ci	return 0;
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_cinla_put_failure:
114262306a36Sopenharmony_ci	nla_nest_cancel(skb, nest);
114362306a36Sopenharmony_ci	return -1;
114462306a36Sopenharmony_ci}
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_cistatic int netem_dump(struct Qdisc *sch, struct sk_buff *skb)
114762306a36Sopenharmony_ci{
114862306a36Sopenharmony_ci	const struct netem_sched_data *q = qdisc_priv(sch);
114962306a36Sopenharmony_ci	struct nlattr *nla = (struct nlattr *) skb_tail_pointer(skb);
115062306a36Sopenharmony_ci	struct tc_netem_qopt qopt;
115162306a36Sopenharmony_ci	struct tc_netem_corr cor;
115262306a36Sopenharmony_ci	struct tc_netem_reorder reorder;
115362306a36Sopenharmony_ci	struct tc_netem_corrupt corrupt;
115462306a36Sopenharmony_ci	struct tc_netem_rate rate;
115562306a36Sopenharmony_ci	struct tc_netem_slot slot;
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci	qopt.latency = min_t(psched_time_t, PSCHED_NS2TICKS(q->latency),
115862306a36Sopenharmony_ci			     UINT_MAX);
115962306a36Sopenharmony_ci	qopt.jitter = min_t(psched_time_t, PSCHED_NS2TICKS(q->jitter),
116062306a36Sopenharmony_ci			    UINT_MAX);
116162306a36Sopenharmony_ci	qopt.limit = q->limit;
116262306a36Sopenharmony_ci	qopt.loss = q->loss;
116362306a36Sopenharmony_ci	qopt.gap = q->gap;
116462306a36Sopenharmony_ci	qopt.duplicate = q->duplicate;
116562306a36Sopenharmony_ci	if (nla_put(skb, TCA_OPTIONS, sizeof(qopt), &qopt))
116662306a36Sopenharmony_ci		goto nla_put_failure;
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	if (nla_put(skb, TCA_NETEM_LATENCY64, sizeof(q->latency), &q->latency))
116962306a36Sopenharmony_ci		goto nla_put_failure;
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	if (nla_put(skb, TCA_NETEM_JITTER64, sizeof(q->jitter), &q->jitter))
117262306a36Sopenharmony_ci		goto nla_put_failure;
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	cor.delay_corr = q->delay_cor.rho;
117562306a36Sopenharmony_ci	cor.loss_corr = q->loss_cor.rho;
117662306a36Sopenharmony_ci	cor.dup_corr = q->dup_cor.rho;
117762306a36Sopenharmony_ci	if (nla_put(skb, TCA_NETEM_CORR, sizeof(cor), &cor))
117862306a36Sopenharmony_ci		goto nla_put_failure;
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	reorder.probability = q->reorder;
118162306a36Sopenharmony_ci	reorder.correlation = q->reorder_cor.rho;
118262306a36Sopenharmony_ci	if (nla_put(skb, TCA_NETEM_REORDER, sizeof(reorder), &reorder))
118362306a36Sopenharmony_ci		goto nla_put_failure;
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	corrupt.probability = q->corrupt;
118662306a36Sopenharmony_ci	corrupt.correlation = q->corrupt_cor.rho;
118762306a36Sopenharmony_ci	if (nla_put(skb, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt))
118862306a36Sopenharmony_ci		goto nla_put_failure;
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	if (q->rate >= (1ULL << 32)) {
119162306a36Sopenharmony_ci		if (nla_put_u64_64bit(skb, TCA_NETEM_RATE64, q->rate,
119262306a36Sopenharmony_ci				      TCA_NETEM_PAD))
119362306a36Sopenharmony_ci			goto nla_put_failure;
119462306a36Sopenharmony_ci		rate.rate = ~0U;
119562306a36Sopenharmony_ci	} else {
119662306a36Sopenharmony_ci		rate.rate = q->rate;
119762306a36Sopenharmony_ci	}
119862306a36Sopenharmony_ci	rate.packet_overhead = q->packet_overhead;
119962306a36Sopenharmony_ci	rate.cell_size = q->cell_size;
120062306a36Sopenharmony_ci	rate.cell_overhead = q->cell_overhead;
120162306a36Sopenharmony_ci	if (nla_put(skb, TCA_NETEM_RATE, sizeof(rate), &rate))
120262306a36Sopenharmony_ci		goto nla_put_failure;
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci	if (q->ecn && nla_put_u32(skb, TCA_NETEM_ECN, q->ecn))
120562306a36Sopenharmony_ci		goto nla_put_failure;
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	if (dump_loss_model(q, skb) != 0)
120862306a36Sopenharmony_ci		goto nla_put_failure;
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	if (q->slot_config.min_delay | q->slot_config.max_delay |
121162306a36Sopenharmony_ci	    q->slot_config.dist_jitter) {
121262306a36Sopenharmony_ci		slot = q->slot_config;
121362306a36Sopenharmony_ci		if (slot.max_packets == INT_MAX)
121462306a36Sopenharmony_ci			slot.max_packets = 0;
121562306a36Sopenharmony_ci		if (slot.max_bytes == INT_MAX)
121662306a36Sopenharmony_ci			slot.max_bytes = 0;
121762306a36Sopenharmony_ci		if (nla_put(skb, TCA_NETEM_SLOT, sizeof(slot), &slot))
121862306a36Sopenharmony_ci			goto nla_put_failure;
121962306a36Sopenharmony_ci	}
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci	if (nla_put_u64_64bit(skb, TCA_NETEM_PRNG_SEED, q->prng.seed,
122262306a36Sopenharmony_ci			      TCA_NETEM_PAD))
122362306a36Sopenharmony_ci		goto nla_put_failure;
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	return nla_nest_end(skb, nla);
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_cinla_put_failure:
122862306a36Sopenharmony_ci	nlmsg_trim(skb, nla);
122962306a36Sopenharmony_ci	return -1;
123062306a36Sopenharmony_ci}
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_cistatic int netem_dump_class(struct Qdisc *sch, unsigned long cl,
123362306a36Sopenharmony_ci			  struct sk_buff *skb, struct tcmsg *tcm)
123462306a36Sopenharmony_ci{
123562306a36Sopenharmony_ci	struct netem_sched_data *q = qdisc_priv(sch);
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci	if (cl != 1 || !q->qdisc) 	/* only one class */
123862306a36Sopenharmony_ci		return -ENOENT;
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	tcm->tcm_handle |= TC_H_MIN(1);
124162306a36Sopenharmony_ci	tcm->tcm_info = q->qdisc->handle;
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	return 0;
124462306a36Sopenharmony_ci}
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_cistatic int netem_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
124762306a36Sopenharmony_ci		     struct Qdisc **old, struct netlink_ext_ack *extack)
124862306a36Sopenharmony_ci{
124962306a36Sopenharmony_ci	struct netem_sched_data *q = qdisc_priv(sch);
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	*old = qdisc_replace(sch, new, &q->qdisc);
125262306a36Sopenharmony_ci	return 0;
125362306a36Sopenharmony_ci}
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_cistatic struct Qdisc *netem_leaf(struct Qdisc *sch, unsigned long arg)
125662306a36Sopenharmony_ci{
125762306a36Sopenharmony_ci	struct netem_sched_data *q = qdisc_priv(sch);
125862306a36Sopenharmony_ci	return q->qdisc;
125962306a36Sopenharmony_ci}
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_cistatic unsigned long netem_find(struct Qdisc *sch, u32 classid)
126262306a36Sopenharmony_ci{
126362306a36Sopenharmony_ci	return 1;
126462306a36Sopenharmony_ci}
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_cistatic void netem_walk(struct Qdisc *sch, struct qdisc_walker *walker)
126762306a36Sopenharmony_ci{
126862306a36Sopenharmony_ci	if (!walker->stop) {
126962306a36Sopenharmony_ci		if (!tc_qdisc_stats_dump(sch, 1, walker))
127062306a36Sopenharmony_ci			return;
127162306a36Sopenharmony_ci	}
127262306a36Sopenharmony_ci}
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_cistatic const struct Qdisc_class_ops netem_class_ops = {
127562306a36Sopenharmony_ci	.graft		=	netem_graft,
127662306a36Sopenharmony_ci	.leaf		=	netem_leaf,
127762306a36Sopenharmony_ci	.find		=	netem_find,
127862306a36Sopenharmony_ci	.walk		=	netem_walk,
127962306a36Sopenharmony_ci	.dump		=	netem_dump_class,
128062306a36Sopenharmony_ci};
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_cistatic struct Qdisc_ops netem_qdisc_ops __read_mostly = {
128362306a36Sopenharmony_ci	.id		=	"netem",
128462306a36Sopenharmony_ci	.cl_ops		=	&netem_class_ops,
128562306a36Sopenharmony_ci	.priv_size	=	sizeof(struct netem_sched_data),
128662306a36Sopenharmony_ci	.enqueue	=	netem_enqueue,
128762306a36Sopenharmony_ci	.dequeue	=	netem_dequeue,
128862306a36Sopenharmony_ci	.peek		=	qdisc_peek_dequeued,
128962306a36Sopenharmony_ci	.init		=	netem_init,
129062306a36Sopenharmony_ci	.reset		=	netem_reset,
129162306a36Sopenharmony_ci	.destroy	=	netem_destroy,
129262306a36Sopenharmony_ci	.change		=	netem_change,
129362306a36Sopenharmony_ci	.dump		=	netem_dump,
129462306a36Sopenharmony_ci	.owner		=	THIS_MODULE,
129562306a36Sopenharmony_ci};
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_cistatic int __init netem_module_init(void)
129962306a36Sopenharmony_ci{
130062306a36Sopenharmony_ci	pr_info("netem: version " VERSION "\n");
130162306a36Sopenharmony_ci	return register_qdisc(&netem_qdisc_ops);
130262306a36Sopenharmony_ci}
130362306a36Sopenharmony_cistatic void __exit netem_module_exit(void)
130462306a36Sopenharmony_ci{
130562306a36Sopenharmony_ci	unregister_qdisc(&netem_qdisc_ops);
130662306a36Sopenharmony_ci}
130762306a36Sopenharmony_cimodule_init(netem_module_init)
130862306a36Sopenharmony_cimodule_exit(netem_module_exit)
130962306a36Sopenharmony_ciMODULE_LICENSE("GPL");
1310