18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * net/sched/sch_netem.c	Network emulator
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  		Many of the algorithms and ideas for this came from
68c2ecf20Sopenharmony_ci *		NIST Net which is not copyrighted.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Authors:	Stephen Hemminger <shemminger@osdl.org>
98c2ecf20Sopenharmony_ci *		Catalin(ux aka Dino) BOIE <catab at umbrella dot ro>
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/mm.h>
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/slab.h>
158c2ecf20Sopenharmony_ci#include <linux/types.h>
168c2ecf20Sopenharmony_ci#include <linux/kernel.h>
178c2ecf20Sopenharmony_ci#include <linux/errno.h>
188c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
198c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
208c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h>
218c2ecf20Sopenharmony_ci#include <linux/reciprocal_div.h>
228c2ecf20Sopenharmony_ci#include <linux/rbtree.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include <net/netlink.h>
258c2ecf20Sopenharmony_ci#include <net/pkt_sched.h>
268c2ecf20Sopenharmony_ci#include <net/inet_ecn.h>
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#define VERSION "1.3"
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci/*	Network Emulation Queuing algorithm.
318c2ecf20Sopenharmony_ci	====================================
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	Sources: [1] Mark Carson, Darrin Santay, "NIST Net - A Linux-based
348c2ecf20Sopenharmony_ci		 Network Emulation Tool
358c2ecf20Sopenharmony_ci		 [2] Luigi Rizzo, DummyNet for FreeBSD
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	 ----------------------------------------------------------------
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	 This started out as a simple way to delay outgoing packets to
408c2ecf20Sopenharmony_ci	 test TCP but has grown to include most of the functionality
418c2ecf20Sopenharmony_ci	 of a full blown network emulator like NISTnet. It can delay
428c2ecf20Sopenharmony_ci	 packets and add random jitter (and correlation). The random
438c2ecf20Sopenharmony_ci	 distribution can be loaded from a table as well to provide
448c2ecf20Sopenharmony_ci	 normal, Pareto, or experimental curves. Packet loss,
458c2ecf20Sopenharmony_ci	 duplication, and reordering can also be emulated.
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	 This qdisc does not do classification that can be handled in
488c2ecf20Sopenharmony_ci	 layering other disciplines.  It does not need to do bandwidth
498c2ecf20Sopenharmony_ci	 control either since that can be handled by using token
508c2ecf20Sopenharmony_ci	 bucket or other rate control.
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci     Correlated Loss Generator models
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	Added generation of correlated loss according to the
558c2ecf20Sopenharmony_ci	"Gilbert-Elliot" model, a 4-state markov model.
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	References:
588c2ecf20Sopenharmony_ci	[1] NetemCLG Home http://netgroup.uniroma2.it/NetemCLG
598c2ecf20Sopenharmony_ci	[2] S. Salsano, F. Ludovici, A. Ordine, "Definition of a general
608c2ecf20Sopenharmony_ci	and intuitive loss model for packet networks and its implementation
618c2ecf20Sopenharmony_ci	in the Netem module in the Linux kernel", available in [1]
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	Authors: Stefano Salsano <stefano.salsano at uniroma2.it
648c2ecf20Sopenharmony_ci		 Fabio Ludovici <fabio.ludovici at yahoo.it>
658c2ecf20Sopenharmony_ci*/
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistruct disttable {
688c2ecf20Sopenharmony_ci	u32  size;
698c2ecf20Sopenharmony_ci	s16 table[];
708c2ecf20Sopenharmony_ci};
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistruct netem_sched_data {
738c2ecf20Sopenharmony_ci	/* internal t(ime)fifo qdisc uses t_root and sch->limit */
748c2ecf20Sopenharmony_ci	struct rb_root t_root;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	/* a linear queue; reduces rbtree rebalancing when jitter is low */
778c2ecf20Sopenharmony_ci	struct sk_buff	*t_head;
788c2ecf20Sopenharmony_ci	struct sk_buff	*t_tail;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	/* optional qdisc for classful handling (NULL at netem init) */
818c2ecf20Sopenharmony_ci	struct Qdisc	*qdisc;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	struct qdisc_watchdog watchdog;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	s64 latency;
868c2ecf20Sopenharmony_ci	s64 jitter;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	u32 loss;
898c2ecf20Sopenharmony_ci	u32 ecn;
908c2ecf20Sopenharmony_ci	u32 limit;
918c2ecf20Sopenharmony_ci	u32 counter;
928c2ecf20Sopenharmony_ci	u32 gap;
938c2ecf20Sopenharmony_ci	u32 duplicate;
948c2ecf20Sopenharmony_ci	u32 reorder;
958c2ecf20Sopenharmony_ci	u32 corrupt;
968c2ecf20Sopenharmony_ci	u64 rate;
978c2ecf20Sopenharmony_ci	s32 packet_overhead;
988c2ecf20Sopenharmony_ci	u32 cell_size;
998c2ecf20Sopenharmony_ci	struct reciprocal_value cell_size_reciprocal;
1008c2ecf20Sopenharmony_ci	s32 cell_overhead;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	struct crndstate {
1038c2ecf20Sopenharmony_ci		u32 last;
1048c2ecf20Sopenharmony_ci		u32 rho;
1058c2ecf20Sopenharmony_ci	} delay_cor, loss_cor, dup_cor, reorder_cor, corrupt_cor;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	struct disttable *delay_dist;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	enum  {
1108c2ecf20Sopenharmony_ci		CLG_RANDOM,
1118c2ecf20Sopenharmony_ci		CLG_4_STATES,
1128c2ecf20Sopenharmony_ci		CLG_GILB_ELL,
1138c2ecf20Sopenharmony_ci	} loss_model;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	enum {
1168c2ecf20Sopenharmony_ci		TX_IN_GAP_PERIOD = 1,
1178c2ecf20Sopenharmony_ci		TX_IN_BURST_PERIOD,
1188c2ecf20Sopenharmony_ci		LOST_IN_GAP_PERIOD,
1198c2ecf20Sopenharmony_ci		LOST_IN_BURST_PERIOD,
1208c2ecf20Sopenharmony_ci	} _4_state_model;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	enum {
1238c2ecf20Sopenharmony_ci		GOOD_STATE = 1,
1248c2ecf20Sopenharmony_ci		BAD_STATE,
1258c2ecf20Sopenharmony_ci	} GE_state_model;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	/* Correlated Loss Generation models */
1288c2ecf20Sopenharmony_ci	struct clgstate {
1298c2ecf20Sopenharmony_ci		/* state of the Markov chain */
1308c2ecf20Sopenharmony_ci		u8 state;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci		/* 4-states and Gilbert-Elliot models */
1338c2ecf20Sopenharmony_ci		u32 a1;	/* p13 for 4-states or p for GE */
1348c2ecf20Sopenharmony_ci		u32 a2;	/* p31 for 4-states or r for GE */
1358c2ecf20Sopenharmony_ci		u32 a3;	/* p32 for 4-states or h for GE */
1368c2ecf20Sopenharmony_ci		u32 a4;	/* p14 for 4-states or 1-k for GE */
1378c2ecf20Sopenharmony_ci		u32 a5; /* p23 used only in 4-states */
1388c2ecf20Sopenharmony_ci	} clg;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	struct tc_netem_slot slot_config;
1418c2ecf20Sopenharmony_ci	struct slotstate {
1428c2ecf20Sopenharmony_ci		u64 slot_next;
1438c2ecf20Sopenharmony_ci		s32 packets_left;
1448c2ecf20Sopenharmony_ci		s32 bytes_left;
1458c2ecf20Sopenharmony_ci	} slot;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	struct disttable *slot_dist;
1488c2ecf20Sopenharmony_ci};
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci/* Time stamp put into socket buffer control block
1518c2ecf20Sopenharmony_ci * Only valid when skbs are in our internal t(ime)fifo queue.
1528c2ecf20Sopenharmony_ci *
1538c2ecf20Sopenharmony_ci * As skb->rbnode uses same storage than skb->next, skb->prev and skb->tstamp,
1548c2ecf20Sopenharmony_ci * and skb->next & skb->prev are scratch space for a qdisc,
1558c2ecf20Sopenharmony_ci * we save skb->tstamp value in skb->cb[] before destroying it.
1568c2ecf20Sopenharmony_ci */
1578c2ecf20Sopenharmony_cistruct netem_skb_cb {
1588c2ecf20Sopenharmony_ci	u64	        time_to_send;
1598c2ecf20Sopenharmony_ci};
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistatic inline struct netem_skb_cb *netem_skb_cb(struct sk_buff *skb)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	/* we assume we can use skb next/prev/tstamp as storage for rb_node */
1648c2ecf20Sopenharmony_ci	qdisc_cb_private_validate(skb, sizeof(struct netem_skb_cb));
1658c2ecf20Sopenharmony_ci	return (struct netem_skb_cb *)qdisc_skb_cb(skb)->data;
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci/* init_crandom - initialize correlated random number generator
1698c2ecf20Sopenharmony_ci * Use entropy source for initial seed.
1708c2ecf20Sopenharmony_ci */
1718c2ecf20Sopenharmony_cistatic void init_crandom(struct crndstate *state, unsigned long rho)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	state->rho = rho;
1748c2ecf20Sopenharmony_ci	state->last = prandom_u32();
1758c2ecf20Sopenharmony_ci}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci/* get_crandom - correlated random number generator
1788c2ecf20Sopenharmony_ci * Next number depends on last value.
1798c2ecf20Sopenharmony_ci * rho is scaled to avoid floating point.
1808c2ecf20Sopenharmony_ci */
1818c2ecf20Sopenharmony_cistatic u32 get_crandom(struct crndstate *state)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	u64 value, rho;
1848c2ecf20Sopenharmony_ci	unsigned long answer;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	if (!state || state->rho == 0)	/* no correlation */
1878c2ecf20Sopenharmony_ci		return prandom_u32();
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	value = prandom_u32();
1908c2ecf20Sopenharmony_ci	rho = (u64)state->rho + 1;
1918c2ecf20Sopenharmony_ci	answer = (value * ((1ull<<32) - rho) + state->last * rho) >> 32;
1928c2ecf20Sopenharmony_ci	state->last = answer;
1938c2ecf20Sopenharmony_ci	return answer;
1948c2ecf20Sopenharmony_ci}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci/* loss_4state - 4-state model loss generator
1978c2ecf20Sopenharmony_ci * Generates losses according to the 4-state Markov chain adopted in
1988c2ecf20Sopenharmony_ci * the GI (General and Intuitive) loss model.
1998c2ecf20Sopenharmony_ci */
2008c2ecf20Sopenharmony_cistatic bool loss_4state(struct netem_sched_data *q)
2018c2ecf20Sopenharmony_ci{
2028c2ecf20Sopenharmony_ci	struct clgstate *clg = &q->clg;
2038c2ecf20Sopenharmony_ci	u32 rnd = prandom_u32();
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	/*
2068c2ecf20Sopenharmony_ci	 * Makes a comparison between rnd and the transition
2078c2ecf20Sopenharmony_ci	 * probabilities outgoing from the current state, then decides the
2088c2ecf20Sopenharmony_ci	 * next state and if the next packet has to be transmitted or lost.
2098c2ecf20Sopenharmony_ci	 * The four states correspond to:
2108c2ecf20Sopenharmony_ci	 *   TX_IN_GAP_PERIOD => successfully transmitted packets within a gap period
2118c2ecf20Sopenharmony_ci	 *   LOST_IN_BURST_PERIOD => isolated losses within a gap period
2128c2ecf20Sopenharmony_ci	 *   LOST_IN_GAP_PERIOD => lost packets within a burst period
2138c2ecf20Sopenharmony_ci	 *   TX_IN_GAP_PERIOD => successfully transmitted packets within a burst period
2148c2ecf20Sopenharmony_ci	 */
2158c2ecf20Sopenharmony_ci	switch (clg->state) {
2168c2ecf20Sopenharmony_ci	case TX_IN_GAP_PERIOD:
2178c2ecf20Sopenharmony_ci		if (rnd < clg->a4) {
2188c2ecf20Sopenharmony_ci			clg->state = LOST_IN_BURST_PERIOD;
2198c2ecf20Sopenharmony_ci			return true;
2208c2ecf20Sopenharmony_ci		} else if (clg->a4 < rnd && rnd < clg->a1 + clg->a4) {
2218c2ecf20Sopenharmony_ci			clg->state = LOST_IN_GAP_PERIOD;
2228c2ecf20Sopenharmony_ci			return true;
2238c2ecf20Sopenharmony_ci		} else if (clg->a1 + clg->a4 < rnd) {
2248c2ecf20Sopenharmony_ci			clg->state = TX_IN_GAP_PERIOD;
2258c2ecf20Sopenharmony_ci		}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci		break;
2288c2ecf20Sopenharmony_ci	case TX_IN_BURST_PERIOD:
2298c2ecf20Sopenharmony_ci		if (rnd < clg->a5) {
2308c2ecf20Sopenharmony_ci			clg->state = LOST_IN_GAP_PERIOD;
2318c2ecf20Sopenharmony_ci			return true;
2328c2ecf20Sopenharmony_ci		} else {
2338c2ecf20Sopenharmony_ci			clg->state = TX_IN_BURST_PERIOD;
2348c2ecf20Sopenharmony_ci		}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci		break;
2378c2ecf20Sopenharmony_ci	case LOST_IN_GAP_PERIOD:
2388c2ecf20Sopenharmony_ci		if (rnd < clg->a3)
2398c2ecf20Sopenharmony_ci			clg->state = TX_IN_BURST_PERIOD;
2408c2ecf20Sopenharmony_ci		else if (clg->a3 < rnd && rnd < clg->a2 + clg->a3) {
2418c2ecf20Sopenharmony_ci			clg->state = TX_IN_GAP_PERIOD;
2428c2ecf20Sopenharmony_ci		} else if (clg->a2 + clg->a3 < rnd) {
2438c2ecf20Sopenharmony_ci			clg->state = LOST_IN_GAP_PERIOD;
2448c2ecf20Sopenharmony_ci			return true;
2458c2ecf20Sopenharmony_ci		}
2468c2ecf20Sopenharmony_ci		break;
2478c2ecf20Sopenharmony_ci	case LOST_IN_BURST_PERIOD:
2488c2ecf20Sopenharmony_ci		clg->state = TX_IN_GAP_PERIOD;
2498c2ecf20Sopenharmony_ci		break;
2508c2ecf20Sopenharmony_ci	}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	return false;
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci/* loss_gilb_ell - Gilbert-Elliot model loss generator
2568c2ecf20Sopenharmony_ci * Generates losses according to the Gilbert-Elliot loss model or
2578c2ecf20Sopenharmony_ci * its special cases  (Gilbert or Simple Gilbert)
2588c2ecf20Sopenharmony_ci *
2598c2ecf20Sopenharmony_ci * Makes a comparison between random number and the transition
2608c2ecf20Sopenharmony_ci * probabilities outgoing from the current state, then decides the
2618c2ecf20Sopenharmony_ci * next state. A second random number is extracted and the comparison
2628c2ecf20Sopenharmony_ci * with the loss probability of the current state decides if the next
2638c2ecf20Sopenharmony_ci * packet will be transmitted or lost.
2648c2ecf20Sopenharmony_ci */
2658c2ecf20Sopenharmony_cistatic bool loss_gilb_ell(struct netem_sched_data *q)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	struct clgstate *clg = &q->clg;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	switch (clg->state) {
2708c2ecf20Sopenharmony_ci	case GOOD_STATE:
2718c2ecf20Sopenharmony_ci		if (prandom_u32() < clg->a1)
2728c2ecf20Sopenharmony_ci			clg->state = BAD_STATE;
2738c2ecf20Sopenharmony_ci		if (prandom_u32() < clg->a4)
2748c2ecf20Sopenharmony_ci			return true;
2758c2ecf20Sopenharmony_ci		break;
2768c2ecf20Sopenharmony_ci	case BAD_STATE:
2778c2ecf20Sopenharmony_ci		if (prandom_u32() < clg->a2)
2788c2ecf20Sopenharmony_ci			clg->state = GOOD_STATE;
2798c2ecf20Sopenharmony_ci		if (prandom_u32() > clg->a3)
2808c2ecf20Sopenharmony_ci			return true;
2818c2ecf20Sopenharmony_ci	}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	return false;
2848c2ecf20Sopenharmony_ci}
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_cistatic bool loss_event(struct netem_sched_data *q)
2878c2ecf20Sopenharmony_ci{
2888c2ecf20Sopenharmony_ci	switch (q->loss_model) {
2898c2ecf20Sopenharmony_ci	case CLG_RANDOM:
2908c2ecf20Sopenharmony_ci		/* Random packet drop 0 => none, ~0 => all */
2918c2ecf20Sopenharmony_ci		return q->loss && q->loss >= get_crandom(&q->loss_cor);
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	case CLG_4_STATES:
2948c2ecf20Sopenharmony_ci		/* 4state loss model algorithm (used also for GI model)
2958c2ecf20Sopenharmony_ci		* Extracts a value from the markov 4 state loss generator,
2968c2ecf20Sopenharmony_ci		* if it is 1 drops a packet and if needed writes the event in
2978c2ecf20Sopenharmony_ci		* the kernel logs
2988c2ecf20Sopenharmony_ci		*/
2998c2ecf20Sopenharmony_ci		return loss_4state(q);
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	case CLG_GILB_ELL:
3028c2ecf20Sopenharmony_ci		/* Gilbert-Elliot loss model algorithm
3038c2ecf20Sopenharmony_ci		* Extracts a value from the Gilbert-Elliot loss generator,
3048c2ecf20Sopenharmony_ci		* if it is 1 drops a packet and if needed writes the event in
3058c2ecf20Sopenharmony_ci		* the kernel logs
3068c2ecf20Sopenharmony_ci		*/
3078c2ecf20Sopenharmony_ci		return loss_gilb_ell(q);
3088c2ecf20Sopenharmony_ci	}
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	return false;	/* not reached */
3118c2ecf20Sopenharmony_ci}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci/* tabledist - return a pseudo-randomly distributed value with mean mu and
3158c2ecf20Sopenharmony_ci * std deviation sigma.  Uses table lookup to approximate the desired
3168c2ecf20Sopenharmony_ci * distribution, and a uniformly-distributed pseudo-random source.
3178c2ecf20Sopenharmony_ci */
3188c2ecf20Sopenharmony_cistatic s64 tabledist(s64 mu, s32 sigma,
3198c2ecf20Sopenharmony_ci		     struct crndstate *state,
3208c2ecf20Sopenharmony_ci		     const struct disttable *dist)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	s64 x;
3238c2ecf20Sopenharmony_ci	long t;
3248c2ecf20Sopenharmony_ci	u32 rnd;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	if (sigma == 0)
3278c2ecf20Sopenharmony_ci		return mu;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	rnd = get_crandom(state);
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	/* default uniform distribution */
3328c2ecf20Sopenharmony_ci	if (dist == NULL)
3338c2ecf20Sopenharmony_ci		return ((rnd % (2 * (u32)sigma)) + mu) - sigma;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	t = dist->table[rnd % dist->size];
3368c2ecf20Sopenharmony_ci	x = (sigma % NETEM_DIST_SCALE) * t;
3378c2ecf20Sopenharmony_ci	if (x >= 0)
3388c2ecf20Sopenharmony_ci		x += NETEM_DIST_SCALE/2;
3398c2ecf20Sopenharmony_ci	else
3408c2ecf20Sopenharmony_ci		x -= NETEM_DIST_SCALE/2;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	return  x / NETEM_DIST_SCALE + (sigma / NETEM_DIST_SCALE) * t + mu;
3438c2ecf20Sopenharmony_ci}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_cistatic u64 packet_time_ns(u64 len, const struct netem_sched_data *q)
3468c2ecf20Sopenharmony_ci{
3478c2ecf20Sopenharmony_ci	len += q->packet_overhead;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	if (q->cell_size) {
3508c2ecf20Sopenharmony_ci		u32 cells = reciprocal_divide(len, q->cell_size_reciprocal);
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci		if (len > cells * q->cell_size)	/* extra cell needed for remainder */
3538c2ecf20Sopenharmony_ci			cells++;
3548c2ecf20Sopenharmony_ci		len = cells * (q->cell_size + q->cell_overhead);
3558c2ecf20Sopenharmony_ci	}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	return div64_u64(len * NSEC_PER_SEC, q->rate);
3588c2ecf20Sopenharmony_ci}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_cistatic void tfifo_reset(struct Qdisc *sch)
3618c2ecf20Sopenharmony_ci{
3628c2ecf20Sopenharmony_ci	struct netem_sched_data *q = qdisc_priv(sch);
3638c2ecf20Sopenharmony_ci	struct rb_node *p = rb_first(&q->t_root);
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	while (p) {
3668c2ecf20Sopenharmony_ci		struct sk_buff *skb = rb_to_skb(p);
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci		p = rb_next(p);
3698c2ecf20Sopenharmony_ci		rb_erase(&skb->rbnode, &q->t_root);
3708c2ecf20Sopenharmony_ci		rtnl_kfree_skbs(skb, skb);
3718c2ecf20Sopenharmony_ci	}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	rtnl_kfree_skbs(q->t_head, q->t_tail);
3748c2ecf20Sopenharmony_ci	q->t_head = NULL;
3758c2ecf20Sopenharmony_ci	q->t_tail = NULL;
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_cistatic void tfifo_enqueue(struct sk_buff *nskb, struct Qdisc *sch)
3798c2ecf20Sopenharmony_ci{
3808c2ecf20Sopenharmony_ci	struct netem_sched_data *q = qdisc_priv(sch);
3818c2ecf20Sopenharmony_ci	u64 tnext = netem_skb_cb(nskb)->time_to_send;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	if (!q->t_tail || tnext >= netem_skb_cb(q->t_tail)->time_to_send) {
3848c2ecf20Sopenharmony_ci		if (q->t_tail)
3858c2ecf20Sopenharmony_ci			q->t_tail->next = nskb;
3868c2ecf20Sopenharmony_ci		else
3878c2ecf20Sopenharmony_ci			q->t_head = nskb;
3888c2ecf20Sopenharmony_ci		q->t_tail = nskb;
3898c2ecf20Sopenharmony_ci	} else {
3908c2ecf20Sopenharmony_ci		struct rb_node **p = &q->t_root.rb_node, *parent = NULL;
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci		while (*p) {
3938c2ecf20Sopenharmony_ci			struct sk_buff *skb;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci			parent = *p;
3968c2ecf20Sopenharmony_ci			skb = rb_to_skb(parent);
3978c2ecf20Sopenharmony_ci			if (tnext >= netem_skb_cb(skb)->time_to_send)
3988c2ecf20Sopenharmony_ci				p = &parent->rb_right;
3998c2ecf20Sopenharmony_ci			else
4008c2ecf20Sopenharmony_ci				p = &parent->rb_left;
4018c2ecf20Sopenharmony_ci		}
4028c2ecf20Sopenharmony_ci		rb_link_node(&nskb->rbnode, parent, p);
4038c2ecf20Sopenharmony_ci		rb_insert_color(&nskb->rbnode, &q->t_root);
4048c2ecf20Sopenharmony_ci	}
4058c2ecf20Sopenharmony_ci	sch->q.qlen++;
4068c2ecf20Sopenharmony_ci}
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci/* netem can't properly corrupt a megapacket (like we get from GSO), so instead
4098c2ecf20Sopenharmony_ci * when we statistically choose to corrupt one, we instead segment it, returning
4108c2ecf20Sopenharmony_ci * the first packet to be corrupted, and re-enqueue the remaining frames
4118c2ecf20Sopenharmony_ci */
4128c2ecf20Sopenharmony_cistatic struct sk_buff *netem_segment(struct sk_buff *skb, struct Qdisc *sch,
4138c2ecf20Sopenharmony_ci				     struct sk_buff **to_free)
4148c2ecf20Sopenharmony_ci{
4158c2ecf20Sopenharmony_ci	struct sk_buff *segs;
4168c2ecf20Sopenharmony_ci	netdev_features_t features = netif_skb_features(skb);
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK);
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	if (IS_ERR_OR_NULL(segs)) {
4218c2ecf20Sopenharmony_ci		qdisc_drop(skb, sch, to_free);
4228c2ecf20Sopenharmony_ci		return NULL;
4238c2ecf20Sopenharmony_ci	}
4248c2ecf20Sopenharmony_ci	consume_skb(skb);
4258c2ecf20Sopenharmony_ci	return segs;
4268c2ecf20Sopenharmony_ci}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci/*
4298c2ecf20Sopenharmony_ci * Insert one skb into qdisc.
4308c2ecf20Sopenharmony_ci * Note: parent depends on return value to account for queue length.
4318c2ecf20Sopenharmony_ci * 	NET_XMIT_DROP: queue length didn't change.
4328c2ecf20Sopenharmony_ci *      NET_XMIT_SUCCESS: one skb was queued.
4338c2ecf20Sopenharmony_ci */
4348c2ecf20Sopenharmony_cistatic int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch,
4358c2ecf20Sopenharmony_ci			 struct sk_buff **to_free)
4368c2ecf20Sopenharmony_ci{
4378c2ecf20Sopenharmony_ci	struct netem_sched_data *q = qdisc_priv(sch);
4388c2ecf20Sopenharmony_ci	/* We don't fill cb now as skb_unshare() may invalidate it */
4398c2ecf20Sopenharmony_ci	struct netem_skb_cb *cb;
4408c2ecf20Sopenharmony_ci	struct sk_buff *skb2;
4418c2ecf20Sopenharmony_ci	struct sk_buff *segs = NULL;
4428c2ecf20Sopenharmony_ci	unsigned int prev_len = qdisc_pkt_len(skb);
4438c2ecf20Sopenharmony_ci	int count = 1;
4448c2ecf20Sopenharmony_ci	int rc = NET_XMIT_SUCCESS;
4458c2ecf20Sopenharmony_ci	int rc_drop = NET_XMIT_DROP;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	/* Do not fool qdisc_drop_all() */
4488c2ecf20Sopenharmony_ci	skb->prev = NULL;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	/* Random duplication */
4518c2ecf20Sopenharmony_ci	if (q->duplicate && q->duplicate >= get_crandom(&q->dup_cor))
4528c2ecf20Sopenharmony_ci		++count;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	/* Drop packet? */
4558c2ecf20Sopenharmony_ci	if (loss_event(q)) {
4568c2ecf20Sopenharmony_ci		if (q->ecn && INET_ECN_set_ce(skb))
4578c2ecf20Sopenharmony_ci			qdisc_qstats_drop(sch); /* mark packet */
4588c2ecf20Sopenharmony_ci		else
4598c2ecf20Sopenharmony_ci			--count;
4608c2ecf20Sopenharmony_ci	}
4618c2ecf20Sopenharmony_ci	if (count == 0) {
4628c2ecf20Sopenharmony_ci		qdisc_qstats_drop(sch);
4638c2ecf20Sopenharmony_ci		__qdisc_drop(skb, to_free);
4648c2ecf20Sopenharmony_ci		return NET_XMIT_SUCCESS | __NET_XMIT_BYPASS;
4658c2ecf20Sopenharmony_ci	}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	/* If a delay is expected, orphan the skb. (orphaning usually takes
4688c2ecf20Sopenharmony_ci	 * place at TX completion time, so _before_ the link transit delay)
4698c2ecf20Sopenharmony_ci	 */
4708c2ecf20Sopenharmony_ci	if (q->latency || q->jitter || q->rate)
4718c2ecf20Sopenharmony_ci		skb_orphan_partial(skb);
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	/*
4748c2ecf20Sopenharmony_ci	 * If we need to duplicate packet, then re-insert at top of the
4758c2ecf20Sopenharmony_ci	 * qdisc tree, since parent queuer expects that only one
4768c2ecf20Sopenharmony_ci	 * skb will be queued.
4778c2ecf20Sopenharmony_ci	 */
4788c2ecf20Sopenharmony_ci	if (count > 1 && (skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) {
4798c2ecf20Sopenharmony_ci		struct Qdisc *rootq = qdisc_root_bh(sch);
4808c2ecf20Sopenharmony_ci		u32 dupsave = q->duplicate; /* prevent duplicating a dup... */
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci		q->duplicate = 0;
4838c2ecf20Sopenharmony_ci		rootq->enqueue(skb2, rootq, to_free);
4848c2ecf20Sopenharmony_ci		q->duplicate = dupsave;
4858c2ecf20Sopenharmony_ci		rc_drop = NET_XMIT_SUCCESS;
4868c2ecf20Sopenharmony_ci	}
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	/*
4898c2ecf20Sopenharmony_ci	 * Randomized packet corruption.
4908c2ecf20Sopenharmony_ci	 * Make copy if needed since we are modifying
4918c2ecf20Sopenharmony_ci	 * If packet is going to be hardware checksummed, then
4928c2ecf20Sopenharmony_ci	 * do it now in software before we mangle it.
4938c2ecf20Sopenharmony_ci	 */
4948c2ecf20Sopenharmony_ci	if (q->corrupt && q->corrupt >= get_crandom(&q->corrupt_cor)) {
4958c2ecf20Sopenharmony_ci		if (skb_is_gso(skb)) {
4968c2ecf20Sopenharmony_ci			skb = netem_segment(skb, sch, to_free);
4978c2ecf20Sopenharmony_ci			if (!skb)
4988c2ecf20Sopenharmony_ci				return rc_drop;
4998c2ecf20Sopenharmony_ci			segs = skb->next;
5008c2ecf20Sopenharmony_ci			skb_mark_not_on_list(skb);
5018c2ecf20Sopenharmony_ci			qdisc_skb_cb(skb)->pkt_len = skb->len;
5028c2ecf20Sopenharmony_ci		}
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci		skb = skb_unshare(skb, GFP_ATOMIC);
5058c2ecf20Sopenharmony_ci		if (unlikely(!skb)) {
5068c2ecf20Sopenharmony_ci			qdisc_qstats_drop(sch);
5078c2ecf20Sopenharmony_ci			goto finish_segs;
5088c2ecf20Sopenharmony_ci		}
5098c2ecf20Sopenharmony_ci		if (skb->ip_summed == CHECKSUM_PARTIAL &&
5108c2ecf20Sopenharmony_ci		    skb_checksum_help(skb)) {
5118c2ecf20Sopenharmony_ci			qdisc_drop(skb, sch, to_free);
5128c2ecf20Sopenharmony_ci			skb = NULL;
5138c2ecf20Sopenharmony_ci			goto finish_segs;
5148c2ecf20Sopenharmony_ci		}
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci		skb->data[prandom_u32() % skb_headlen(skb)] ^=
5178c2ecf20Sopenharmony_ci			1<<(prandom_u32() % 8);
5188c2ecf20Sopenharmony_ci	}
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	if (unlikely(sch->q.qlen >= sch->limit)) {
5218c2ecf20Sopenharmony_ci		/* re-link segs, so that qdisc_drop_all() frees them all */
5228c2ecf20Sopenharmony_ci		skb->next = segs;
5238c2ecf20Sopenharmony_ci		qdisc_drop_all(skb, sch, to_free);
5248c2ecf20Sopenharmony_ci		return rc_drop;
5258c2ecf20Sopenharmony_ci	}
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	qdisc_qstats_backlog_inc(sch, skb);
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	cb = netem_skb_cb(skb);
5308c2ecf20Sopenharmony_ci	if (q->gap == 0 ||		/* not doing reordering */
5318c2ecf20Sopenharmony_ci	    q->counter < q->gap - 1 ||	/* inside last reordering gap */
5328c2ecf20Sopenharmony_ci	    q->reorder < get_crandom(&q->reorder_cor)) {
5338c2ecf20Sopenharmony_ci		u64 now;
5348c2ecf20Sopenharmony_ci		s64 delay;
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci		delay = tabledist(q->latency, q->jitter,
5378c2ecf20Sopenharmony_ci				  &q->delay_cor, q->delay_dist);
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci		now = ktime_get_ns();
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci		if (q->rate) {
5428c2ecf20Sopenharmony_ci			struct netem_skb_cb *last = NULL;
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci			if (sch->q.tail)
5458c2ecf20Sopenharmony_ci				last = netem_skb_cb(sch->q.tail);
5468c2ecf20Sopenharmony_ci			if (q->t_root.rb_node) {
5478c2ecf20Sopenharmony_ci				struct sk_buff *t_skb;
5488c2ecf20Sopenharmony_ci				struct netem_skb_cb *t_last;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci				t_skb = skb_rb_last(&q->t_root);
5518c2ecf20Sopenharmony_ci				t_last = netem_skb_cb(t_skb);
5528c2ecf20Sopenharmony_ci				if (!last ||
5538c2ecf20Sopenharmony_ci				    t_last->time_to_send > last->time_to_send)
5548c2ecf20Sopenharmony_ci					last = t_last;
5558c2ecf20Sopenharmony_ci			}
5568c2ecf20Sopenharmony_ci			if (q->t_tail) {
5578c2ecf20Sopenharmony_ci				struct netem_skb_cb *t_last =
5588c2ecf20Sopenharmony_ci					netem_skb_cb(q->t_tail);
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci				if (!last ||
5618c2ecf20Sopenharmony_ci				    t_last->time_to_send > last->time_to_send)
5628c2ecf20Sopenharmony_ci					last = t_last;
5638c2ecf20Sopenharmony_ci			}
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci			if (last) {
5668c2ecf20Sopenharmony_ci				/*
5678c2ecf20Sopenharmony_ci				 * Last packet in queue is reference point (now),
5688c2ecf20Sopenharmony_ci				 * calculate this time bonus and subtract
5698c2ecf20Sopenharmony_ci				 * from delay.
5708c2ecf20Sopenharmony_ci				 */
5718c2ecf20Sopenharmony_ci				delay -= last->time_to_send - now;
5728c2ecf20Sopenharmony_ci				delay = max_t(s64, 0, delay);
5738c2ecf20Sopenharmony_ci				now = last->time_to_send;
5748c2ecf20Sopenharmony_ci			}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci			delay += packet_time_ns(qdisc_pkt_len(skb), q);
5778c2ecf20Sopenharmony_ci		}
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci		cb->time_to_send = now + delay;
5808c2ecf20Sopenharmony_ci		++q->counter;
5818c2ecf20Sopenharmony_ci		tfifo_enqueue(skb, sch);
5828c2ecf20Sopenharmony_ci	} else {
5838c2ecf20Sopenharmony_ci		/*
5848c2ecf20Sopenharmony_ci		 * Do re-ordering by putting one out of N packets at the front
5858c2ecf20Sopenharmony_ci		 * of the queue.
5868c2ecf20Sopenharmony_ci		 */
5878c2ecf20Sopenharmony_ci		cb->time_to_send = ktime_get_ns();
5888c2ecf20Sopenharmony_ci		q->counter = 0;
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci		__qdisc_enqueue_head(skb, &sch->q);
5918c2ecf20Sopenharmony_ci		sch->qstats.requeues++;
5928c2ecf20Sopenharmony_ci	}
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_cifinish_segs:
5958c2ecf20Sopenharmony_ci	if (segs) {
5968c2ecf20Sopenharmony_ci		unsigned int len, last_len;
5978c2ecf20Sopenharmony_ci		int nb;
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci		len = skb ? skb->len : 0;
6008c2ecf20Sopenharmony_ci		nb = skb ? 1 : 0;
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci		while (segs) {
6038c2ecf20Sopenharmony_ci			skb2 = segs->next;
6048c2ecf20Sopenharmony_ci			skb_mark_not_on_list(segs);
6058c2ecf20Sopenharmony_ci			qdisc_skb_cb(segs)->pkt_len = segs->len;
6068c2ecf20Sopenharmony_ci			last_len = segs->len;
6078c2ecf20Sopenharmony_ci			rc = qdisc_enqueue(segs, sch, to_free);
6088c2ecf20Sopenharmony_ci			if (rc != NET_XMIT_SUCCESS) {
6098c2ecf20Sopenharmony_ci				if (net_xmit_drop_count(rc))
6108c2ecf20Sopenharmony_ci					qdisc_qstats_drop(sch);
6118c2ecf20Sopenharmony_ci			} else {
6128c2ecf20Sopenharmony_ci				nb++;
6138c2ecf20Sopenharmony_ci				len += last_len;
6148c2ecf20Sopenharmony_ci			}
6158c2ecf20Sopenharmony_ci			segs = skb2;
6168c2ecf20Sopenharmony_ci		}
6178c2ecf20Sopenharmony_ci		/* Parent qdiscs accounted for 1 skb of size @prev_len */
6188c2ecf20Sopenharmony_ci		qdisc_tree_reduce_backlog(sch, -(nb - 1), -(len - prev_len));
6198c2ecf20Sopenharmony_ci	} else if (!skb) {
6208c2ecf20Sopenharmony_ci		return NET_XMIT_DROP;
6218c2ecf20Sopenharmony_ci	}
6228c2ecf20Sopenharmony_ci	return NET_XMIT_SUCCESS;
6238c2ecf20Sopenharmony_ci}
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci/* Delay the next round with a new future slot with a
6268c2ecf20Sopenharmony_ci * correct number of bytes and packets.
6278c2ecf20Sopenharmony_ci */
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_cistatic void get_slot_next(struct netem_sched_data *q, u64 now)
6308c2ecf20Sopenharmony_ci{
6318c2ecf20Sopenharmony_ci	s64 next_delay;
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	if (!q->slot_dist)
6348c2ecf20Sopenharmony_ci		next_delay = q->slot_config.min_delay +
6358c2ecf20Sopenharmony_ci				(prandom_u32() *
6368c2ecf20Sopenharmony_ci				 (q->slot_config.max_delay -
6378c2ecf20Sopenharmony_ci				  q->slot_config.min_delay) >> 32);
6388c2ecf20Sopenharmony_ci	else
6398c2ecf20Sopenharmony_ci		next_delay = tabledist(q->slot_config.dist_delay,
6408c2ecf20Sopenharmony_ci				       (s32)(q->slot_config.dist_jitter),
6418c2ecf20Sopenharmony_ci				       NULL, q->slot_dist);
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	q->slot.slot_next = now + next_delay;
6448c2ecf20Sopenharmony_ci	q->slot.packets_left = q->slot_config.max_packets;
6458c2ecf20Sopenharmony_ci	q->slot.bytes_left = q->slot_config.max_bytes;
6468c2ecf20Sopenharmony_ci}
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_cistatic struct sk_buff *netem_peek(struct netem_sched_data *q)
6498c2ecf20Sopenharmony_ci{
6508c2ecf20Sopenharmony_ci	struct sk_buff *skb = skb_rb_first(&q->t_root);
6518c2ecf20Sopenharmony_ci	u64 t1, t2;
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	if (!skb)
6548c2ecf20Sopenharmony_ci		return q->t_head;
6558c2ecf20Sopenharmony_ci	if (!q->t_head)
6568c2ecf20Sopenharmony_ci		return skb;
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	t1 = netem_skb_cb(skb)->time_to_send;
6598c2ecf20Sopenharmony_ci	t2 = netem_skb_cb(q->t_head)->time_to_send;
6608c2ecf20Sopenharmony_ci	if (t1 < t2)
6618c2ecf20Sopenharmony_ci		return skb;
6628c2ecf20Sopenharmony_ci	return q->t_head;
6638c2ecf20Sopenharmony_ci}
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_cistatic void netem_erase_head(struct netem_sched_data *q, struct sk_buff *skb)
6668c2ecf20Sopenharmony_ci{
6678c2ecf20Sopenharmony_ci	if (skb == q->t_head) {
6688c2ecf20Sopenharmony_ci		q->t_head = skb->next;
6698c2ecf20Sopenharmony_ci		if (!q->t_head)
6708c2ecf20Sopenharmony_ci			q->t_tail = NULL;
6718c2ecf20Sopenharmony_ci	} else {
6728c2ecf20Sopenharmony_ci		rb_erase(&skb->rbnode, &q->t_root);
6738c2ecf20Sopenharmony_ci	}
6748c2ecf20Sopenharmony_ci}
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_cistatic struct sk_buff *netem_dequeue(struct Qdisc *sch)
6778c2ecf20Sopenharmony_ci{
6788c2ecf20Sopenharmony_ci	struct netem_sched_data *q = qdisc_priv(sch);
6798c2ecf20Sopenharmony_ci	struct sk_buff *skb;
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_citfifo_dequeue:
6828c2ecf20Sopenharmony_ci	skb = __qdisc_dequeue_head(&sch->q);
6838c2ecf20Sopenharmony_ci	if (skb) {
6848c2ecf20Sopenharmony_ci		qdisc_qstats_backlog_dec(sch, skb);
6858c2ecf20Sopenharmony_cideliver:
6868c2ecf20Sopenharmony_ci		qdisc_bstats_update(sch, skb);
6878c2ecf20Sopenharmony_ci		return skb;
6888c2ecf20Sopenharmony_ci	}
6898c2ecf20Sopenharmony_ci	skb = netem_peek(q);
6908c2ecf20Sopenharmony_ci	if (skb) {
6918c2ecf20Sopenharmony_ci		u64 time_to_send;
6928c2ecf20Sopenharmony_ci		u64 now = ktime_get_ns();
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci		/* if more time remaining? */
6958c2ecf20Sopenharmony_ci		time_to_send = netem_skb_cb(skb)->time_to_send;
6968c2ecf20Sopenharmony_ci		if (q->slot.slot_next && q->slot.slot_next < time_to_send)
6978c2ecf20Sopenharmony_ci			get_slot_next(q, now);
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci		if (time_to_send <= now && q->slot.slot_next <= now) {
7008c2ecf20Sopenharmony_ci			netem_erase_head(q, skb);
7018c2ecf20Sopenharmony_ci			sch->q.qlen--;
7028c2ecf20Sopenharmony_ci			qdisc_qstats_backlog_dec(sch, skb);
7038c2ecf20Sopenharmony_ci			skb->next = NULL;
7048c2ecf20Sopenharmony_ci			skb->prev = NULL;
7058c2ecf20Sopenharmony_ci			/* skb->dev shares skb->rbnode area,
7068c2ecf20Sopenharmony_ci			 * we need to restore its value.
7078c2ecf20Sopenharmony_ci			 */
7088c2ecf20Sopenharmony_ci			skb->dev = qdisc_dev(sch);
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci			if (q->slot.slot_next) {
7118c2ecf20Sopenharmony_ci				q->slot.packets_left--;
7128c2ecf20Sopenharmony_ci				q->slot.bytes_left -= qdisc_pkt_len(skb);
7138c2ecf20Sopenharmony_ci				if (q->slot.packets_left <= 0 ||
7148c2ecf20Sopenharmony_ci				    q->slot.bytes_left <= 0)
7158c2ecf20Sopenharmony_ci					get_slot_next(q, now);
7168c2ecf20Sopenharmony_ci			}
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci			if (q->qdisc) {
7198c2ecf20Sopenharmony_ci				unsigned int pkt_len = qdisc_pkt_len(skb);
7208c2ecf20Sopenharmony_ci				struct sk_buff *to_free = NULL;
7218c2ecf20Sopenharmony_ci				int err;
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci				err = qdisc_enqueue(skb, q->qdisc, &to_free);
7248c2ecf20Sopenharmony_ci				kfree_skb_list(to_free);
7258c2ecf20Sopenharmony_ci				if (err != NET_XMIT_SUCCESS) {
7268c2ecf20Sopenharmony_ci					if (net_xmit_drop_count(err))
7278c2ecf20Sopenharmony_ci						qdisc_qstats_drop(sch);
7288c2ecf20Sopenharmony_ci					qdisc_tree_reduce_backlog(sch, 1, pkt_len);
7298c2ecf20Sopenharmony_ci				}
7308c2ecf20Sopenharmony_ci				goto tfifo_dequeue;
7318c2ecf20Sopenharmony_ci			}
7328c2ecf20Sopenharmony_ci			goto deliver;
7338c2ecf20Sopenharmony_ci		}
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci		if (q->qdisc) {
7368c2ecf20Sopenharmony_ci			skb = q->qdisc->ops->dequeue(q->qdisc);
7378c2ecf20Sopenharmony_ci			if (skb)
7388c2ecf20Sopenharmony_ci				goto deliver;
7398c2ecf20Sopenharmony_ci		}
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci		qdisc_watchdog_schedule_ns(&q->watchdog,
7428c2ecf20Sopenharmony_ci					   max(time_to_send,
7438c2ecf20Sopenharmony_ci					       q->slot.slot_next));
7448c2ecf20Sopenharmony_ci	}
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	if (q->qdisc) {
7478c2ecf20Sopenharmony_ci		skb = q->qdisc->ops->dequeue(q->qdisc);
7488c2ecf20Sopenharmony_ci		if (skb)
7498c2ecf20Sopenharmony_ci			goto deliver;
7508c2ecf20Sopenharmony_ci	}
7518c2ecf20Sopenharmony_ci	return NULL;
7528c2ecf20Sopenharmony_ci}
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_cistatic void netem_reset(struct Qdisc *sch)
7558c2ecf20Sopenharmony_ci{
7568c2ecf20Sopenharmony_ci	struct netem_sched_data *q = qdisc_priv(sch);
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	qdisc_reset_queue(sch);
7598c2ecf20Sopenharmony_ci	tfifo_reset(sch);
7608c2ecf20Sopenharmony_ci	if (q->qdisc)
7618c2ecf20Sopenharmony_ci		qdisc_reset(q->qdisc);
7628c2ecf20Sopenharmony_ci	qdisc_watchdog_cancel(&q->watchdog);
7638c2ecf20Sopenharmony_ci}
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_cistatic void dist_free(struct disttable *d)
7668c2ecf20Sopenharmony_ci{
7678c2ecf20Sopenharmony_ci	kvfree(d);
7688c2ecf20Sopenharmony_ci}
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci/*
7718c2ecf20Sopenharmony_ci * Distribution data is a variable size payload containing
7728c2ecf20Sopenharmony_ci * signed 16 bit values.
7738c2ecf20Sopenharmony_ci */
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_cistatic int get_dist_table(struct disttable **tbl, const struct nlattr *attr)
7768c2ecf20Sopenharmony_ci{
7778c2ecf20Sopenharmony_ci	size_t n = nla_len(attr)/sizeof(__s16);
7788c2ecf20Sopenharmony_ci	const __s16 *data = nla_data(attr);
7798c2ecf20Sopenharmony_ci	struct disttable *d;
7808c2ecf20Sopenharmony_ci	int i;
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	if (!n || n > NETEM_DIST_MAX)
7838c2ecf20Sopenharmony_ci		return -EINVAL;
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci	d = kvmalloc(sizeof(struct disttable) + n * sizeof(s16), GFP_KERNEL);
7868c2ecf20Sopenharmony_ci	if (!d)
7878c2ecf20Sopenharmony_ci		return -ENOMEM;
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	d->size = n;
7908c2ecf20Sopenharmony_ci	for (i = 0; i < n; i++)
7918c2ecf20Sopenharmony_ci		d->table[i] = data[i];
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	*tbl = d;
7948c2ecf20Sopenharmony_ci	return 0;
7958c2ecf20Sopenharmony_ci}
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_cistatic void get_slot(struct netem_sched_data *q, const struct nlattr *attr)
7988c2ecf20Sopenharmony_ci{
7998c2ecf20Sopenharmony_ci	const struct tc_netem_slot *c = nla_data(attr);
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci	q->slot_config = *c;
8028c2ecf20Sopenharmony_ci	if (q->slot_config.max_packets == 0)
8038c2ecf20Sopenharmony_ci		q->slot_config.max_packets = INT_MAX;
8048c2ecf20Sopenharmony_ci	if (q->slot_config.max_bytes == 0)
8058c2ecf20Sopenharmony_ci		q->slot_config.max_bytes = INT_MAX;
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	/* capping dist_jitter to the range acceptable by tabledist() */
8088c2ecf20Sopenharmony_ci	q->slot_config.dist_jitter = min_t(__s64, INT_MAX, abs(q->slot_config.dist_jitter));
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	q->slot.packets_left = q->slot_config.max_packets;
8118c2ecf20Sopenharmony_ci	q->slot.bytes_left = q->slot_config.max_bytes;
8128c2ecf20Sopenharmony_ci	if (q->slot_config.min_delay | q->slot_config.max_delay |
8138c2ecf20Sopenharmony_ci	    q->slot_config.dist_jitter)
8148c2ecf20Sopenharmony_ci		q->slot.slot_next = ktime_get_ns();
8158c2ecf20Sopenharmony_ci	else
8168c2ecf20Sopenharmony_ci		q->slot.slot_next = 0;
8178c2ecf20Sopenharmony_ci}
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_cistatic void get_correlation(struct netem_sched_data *q, const struct nlattr *attr)
8208c2ecf20Sopenharmony_ci{
8218c2ecf20Sopenharmony_ci	const struct tc_netem_corr *c = nla_data(attr);
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	init_crandom(&q->delay_cor, c->delay_corr);
8248c2ecf20Sopenharmony_ci	init_crandom(&q->loss_cor, c->loss_corr);
8258c2ecf20Sopenharmony_ci	init_crandom(&q->dup_cor, c->dup_corr);
8268c2ecf20Sopenharmony_ci}
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_cistatic void get_reorder(struct netem_sched_data *q, const struct nlattr *attr)
8298c2ecf20Sopenharmony_ci{
8308c2ecf20Sopenharmony_ci	const struct tc_netem_reorder *r = nla_data(attr);
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci	q->reorder = r->probability;
8338c2ecf20Sopenharmony_ci	init_crandom(&q->reorder_cor, r->correlation);
8348c2ecf20Sopenharmony_ci}
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_cistatic void get_corrupt(struct netem_sched_data *q, const struct nlattr *attr)
8378c2ecf20Sopenharmony_ci{
8388c2ecf20Sopenharmony_ci	const struct tc_netem_corrupt *r = nla_data(attr);
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	q->corrupt = r->probability;
8418c2ecf20Sopenharmony_ci	init_crandom(&q->corrupt_cor, r->correlation);
8428c2ecf20Sopenharmony_ci}
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_cistatic void get_rate(struct netem_sched_data *q, const struct nlattr *attr)
8458c2ecf20Sopenharmony_ci{
8468c2ecf20Sopenharmony_ci	const struct tc_netem_rate *r = nla_data(attr);
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	q->rate = r->rate;
8498c2ecf20Sopenharmony_ci	q->packet_overhead = r->packet_overhead;
8508c2ecf20Sopenharmony_ci	q->cell_size = r->cell_size;
8518c2ecf20Sopenharmony_ci	q->cell_overhead = r->cell_overhead;
8528c2ecf20Sopenharmony_ci	if (q->cell_size)
8538c2ecf20Sopenharmony_ci		q->cell_size_reciprocal = reciprocal_value(q->cell_size);
8548c2ecf20Sopenharmony_ci	else
8558c2ecf20Sopenharmony_ci		q->cell_size_reciprocal = (struct reciprocal_value) { 0 };
8568c2ecf20Sopenharmony_ci}
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_cistatic int get_loss_clg(struct netem_sched_data *q, const struct nlattr *attr)
8598c2ecf20Sopenharmony_ci{
8608c2ecf20Sopenharmony_ci	const struct nlattr *la;
8618c2ecf20Sopenharmony_ci	int rem;
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	nla_for_each_nested(la, attr, rem) {
8648c2ecf20Sopenharmony_ci		u16 type = nla_type(la);
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci		switch (type) {
8678c2ecf20Sopenharmony_ci		case NETEM_LOSS_GI: {
8688c2ecf20Sopenharmony_ci			const struct tc_netem_gimodel *gi = nla_data(la);
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci			if (nla_len(la) < sizeof(struct tc_netem_gimodel)) {
8718c2ecf20Sopenharmony_ci				pr_info("netem: incorrect gi model size\n");
8728c2ecf20Sopenharmony_ci				return -EINVAL;
8738c2ecf20Sopenharmony_ci			}
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci			q->loss_model = CLG_4_STATES;
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci			q->clg.state = TX_IN_GAP_PERIOD;
8788c2ecf20Sopenharmony_ci			q->clg.a1 = gi->p13;
8798c2ecf20Sopenharmony_ci			q->clg.a2 = gi->p31;
8808c2ecf20Sopenharmony_ci			q->clg.a3 = gi->p32;
8818c2ecf20Sopenharmony_ci			q->clg.a4 = gi->p14;
8828c2ecf20Sopenharmony_ci			q->clg.a5 = gi->p23;
8838c2ecf20Sopenharmony_ci			break;
8848c2ecf20Sopenharmony_ci		}
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci		case NETEM_LOSS_GE: {
8878c2ecf20Sopenharmony_ci			const struct tc_netem_gemodel *ge = nla_data(la);
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci			if (nla_len(la) < sizeof(struct tc_netem_gemodel)) {
8908c2ecf20Sopenharmony_ci				pr_info("netem: incorrect ge model size\n");
8918c2ecf20Sopenharmony_ci				return -EINVAL;
8928c2ecf20Sopenharmony_ci			}
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci			q->loss_model = CLG_GILB_ELL;
8958c2ecf20Sopenharmony_ci			q->clg.state = GOOD_STATE;
8968c2ecf20Sopenharmony_ci			q->clg.a1 = ge->p;
8978c2ecf20Sopenharmony_ci			q->clg.a2 = ge->r;
8988c2ecf20Sopenharmony_ci			q->clg.a3 = ge->h;
8998c2ecf20Sopenharmony_ci			q->clg.a4 = ge->k1;
9008c2ecf20Sopenharmony_ci			break;
9018c2ecf20Sopenharmony_ci		}
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci		default:
9048c2ecf20Sopenharmony_ci			pr_info("netem: unknown loss type %u\n", type);
9058c2ecf20Sopenharmony_ci			return -EINVAL;
9068c2ecf20Sopenharmony_ci		}
9078c2ecf20Sopenharmony_ci	}
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	return 0;
9108c2ecf20Sopenharmony_ci}
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_cistatic const struct nla_policy netem_policy[TCA_NETEM_MAX + 1] = {
9138c2ecf20Sopenharmony_ci	[TCA_NETEM_CORR]	= { .len = sizeof(struct tc_netem_corr) },
9148c2ecf20Sopenharmony_ci	[TCA_NETEM_REORDER]	= { .len = sizeof(struct tc_netem_reorder) },
9158c2ecf20Sopenharmony_ci	[TCA_NETEM_CORRUPT]	= { .len = sizeof(struct tc_netem_corrupt) },
9168c2ecf20Sopenharmony_ci	[TCA_NETEM_RATE]	= { .len = sizeof(struct tc_netem_rate) },
9178c2ecf20Sopenharmony_ci	[TCA_NETEM_LOSS]	= { .type = NLA_NESTED },
9188c2ecf20Sopenharmony_ci	[TCA_NETEM_ECN]		= { .type = NLA_U32 },
9198c2ecf20Sopenharmony_ci	[TCA_NETEM_RATE64]	= { .type = NLA_U64 },
9208c2ecf20Sopenharmony_ci	[TCA_NETEM_LATENCY64]	= { .type = NLA_S64 },
9218c2ecf20Sopenharmony_ci	[TCA_NETEM_JITTER64]	= { .type = NLA_S64 },
9228c2ecf20Sopenharmony_ci	[TCA_NETEM_SLOT]	= { .len = sizeof(struct tc_netem_slot) },
9238c2ecf20Sopenharmony_ci};
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_cistatic int parse_attr(struct nlattr *tb[], int maxtype, struct nlattr *nla,
9268c2ecf20Sopenharmony_ci		      const struct nla_policy *policy, int len)
9278c2ecf20Sopenharmony_ci{
9288c2ecf20Sopenharmony_ci	int nested_len = nla_len(nla) - NLA_ALIGN(len);
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	if (nested_len < 0) {
9318c2ecf20Sopenharmony_ci		pr_info("netem: invalid attributes len %d\n", nested_len);
9328c2ecf20Sopenharmony_ci		return -EINVAL;
9338c2ecf20Sopenharmony_ci	}
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci	if (nested_len >= nla_attr_size(0))
9368c2ecf20Sopenharmony_ci		return nla_parse_deprecated(tb, maxtype,
9378c2ecf20Sopenharmony_ci					    nla_data(nla) + NLA_ALIGN(len),
9388c2ecf20Sopenharmony_ci					    nested_len, policy, NULL);
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci	memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
9418c2ecf20Sopenharmony_ci	return 0;
9428c2ecf20Sopenharmony_ci}
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci/* Parse netlink message to set options */
9458c2ecf20Sopenharmony_cistatic int netem_change(struct Qdisc *sch, struct nlattr *opt,
9468c2ecf20Sopenharmony_ci			struct netlink_ext_ack *extack)
9478c2ecf20Sopenharmony_ci{
9488c2ecf20Sopenharmony_ci	struct netem_sched_data *q = qdisc_priv(sch);
9498c2ecf20Sopenharmony_ci	struct nlattr *tb[TCA_NETEM_MAX + 1];
9508c2ecf20Sopenharmony_ci	struct disttable *delay_dist = NULL;
9518c2ecf20Sopenharmony_ci	struct disttable *slot_dist = NULL;
9528c2ecf20Sopenharmony_ci	struct tc_netem_qopt *qopt;
9538c2ecf20Sopenharmony_ci	struct clgstate old_clg;
9548c2ecf20Sopenharmony_ci	int old_loss_model = CLG_RANDOM;
9558c2ecf20Sopenharmony_ci	int ret;
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci	if (opt == NULL)
9588c2ecf20Sopenharmony_ci		return -EINVAL;
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	qopt = nla_data(opt);
9618c2ecf20Sopenharmony_ci	ret = parse_attr(tb, TCA_NETEM_MAX, opt, netem_policy, sizeof(*qopt));
9628c2ecf20Sopenharmony_ci	if (ret < 0)
9638c2ecf20Sopenharmony_ci		return ret;
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	if (tb[TCA_NETEM_DELAY_DIST]) {
9668c2ecf20Sopenharmony_ci		ret = get_dist_table(&delay_dist, tb[TCA_NETEM_DELAY_DIST]);
9678c2ecf20Sopenharmony_ci		if (ret)
9688c2ecf20Sopenharmony_ci			goto table_free;
9698c2ecf20Sopenharmony_ci	}
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci	if (tb[TCA_NETEM_SLOT_DIST]) {
9728c2ecf20Sopenharmony_ci		ret = get_dist_table(&slot_dist, tb[TCA_NETEM_SLOT_DIST]);
9738c2ecf20Sopenharmony_ci		if (ret)
9748c2ecf20Sopenharmony_ci			goto table_free;
9758c2ecf20Sopenharmony_ci	}
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci	sch_tree_lock(sch);
9788c2ecf20Sopenharmony_ci	/* backup q->clg and q->loss_model */
9798c2ecf20Sopenharmony_ci	old_clg = q->clg;
9808c2ecf20Sopenharmony_ci	old_loss_model = q->loss_model;
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci	if (tb[TCA_NETEM_LOSS]) {
9838c2ecf20Sopenharmony_ci		ret = get_loss_clg(q, tb[TCA_NETEM_LOSS]);
9848c2ecf20Sopenharmony_ci		if (ret) {
9858c2ecf20Sopenharmony_ci			q->loss_model = old_loss_model;
9868c2ecf20Sopenharmony_ci			q->clg = old_clg;
9878c2ecf20Sopenharmony_ci			goto unlock;
9888c2ecf20Sopenharmony_ci		}
9898c2ecf20Sopenharmony_ci	} else {
9908c2ecf20Sopenharmony_ci		q->loss_model = CLG_RANDOM;
9918c2ecf20Sopenharmony_ci	}
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci	if (delay_dist)
9948c2ecf20Sopenharmony_ci		swap(q->delay_dist, delay_dist);
9958c2ecf20Sopenharmony_ci	if (slot_dist)
9968c2ecf20Sopenharmony_ci		swap(q->slot_dist, slot_dist);
9978c2ecf20Sopenharmony_ci	sch->limit = qopt->limit;
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci	q->latency = PSCHED_TICKS2NS(qopt->latency);
10008c2ecf20Sopenharmony_ci	q->jitter = PSCHED_TICKS2NS(qopt->jitter);
10018c2ecf20Sopenharmony_ci	q->limit = qopt->limit;
10028c2ecf20Sopenharmony_ci	q->gap = qopt->gap;
10038c2ecf20Sopenharmony_ci	q->counter = 0;
10048c2ecf20Sopenharmony_ci	q->loss = qopt->loss;
10058c2ecf20Sopenharmony_ci	q->duplicate = qopt->duplicate;
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci	/* for compatibility with earlier versions.
10088c2ecf20Sopenharmony_ci	 * if gap is set, need to assume 100% probability
10098c2ecf20Sopenharmony_ci	 */
10108c2ecf20Sopenharmony_ci	if (q->gap)
10118c2ecf20Sopenharmony_ci		q->reorder = ~0;
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci	if (tb[TCA_NETEM_CORR])
10148c2ecf20Sopenharmony_ci		get_correlation(q, tb[TCA_NETEM_CORR]);
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	if (tb[TCA_NETEM_REORDER])
10178c2ecf20Sopenharmony_ci		get_reorder(q, tb[TCA_NETEM_REORDER]);
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci	if (tb[TCA_NETEM_CORRUPT])
10208c2ecf20Sopenharmony_ci		get_corrupt(q, tb[TCA_NETEM_CORRUPT]);
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci	if (tb[TCA_NETEM_RATE])
10238c2ecf20Sopenharmony_ci		get_rate(q, tb[TCA_NETEM_RATE]);
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci	if (tb[TCA_NETEM_RATE64])
10268c2ecf20Sopenharmony_ci		q->rate = max_t(u64, q->rate,
10278c2ecf20Sopenharmony_ci				nla_get_u64(tb[TCA_NETEM_RATE64]));
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	if (tb[TCA_NETEM_LATENCY64])
10308c2ecf20Sopenharmony_ci		q->latency = nla_get_s64(tb[TCA_NETEM_LATENCY64]);
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci	if (tb[TCA_NETEM_JITTER64])
10338c2ecf20Sopenharmony_ci		q->jitter = nla_get_s64(tb[TCA_NETEM_JITTER64]);
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	if (tb[TCA_NETEM_ECN])
10368c2ecf20Sopenharmony_ci		q->ecn = nla_get_u32(tb[TCA_NETEM_ECN]);
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci	if (tb[TCA_NETEM_SLOT])
10398c2ecf20Sopenharmony_ci		get_slot(q, tb[TCA_NETEM_SLOT]);
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci	/* capping jitter to the range acceptable by tabledist() */
10428c2ecf20Sopenharmony_ci	q->jitter = min_t(s64, abs(q->jitter), INT_MAX);
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_ciunlock:
10458c2ecf20Sopenharmony_ci	sch_tree_unlock(sch);
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_citable_free:
10488c2ecf20Sopenharmony_ci	dist_free(delay_dist);
10498c2ecf20Sopenharmony_ci	dist_free(slot_dist);
10508c2ecf20Sopenharmony_ci	return ret;
10518c2ecf20Sopenharmony_ci}
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_cistatic int netem_init(struct Qdisc *sch, struct nlattr *opt,
10548c2ecf20Sopenharmony_ci		      struct netlink_ext_ack *extack)
10558c2ecf20Sopenharmony_ci{
10568c2ecf20Sopenharmony_ci	struct netem_sched_data *q = qdisc_priv(sch);
10578c2ecf20Sopenharmony_ci	int ret;
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci	qdisc_watchdog_init(&q->watchdog, sch);
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci	if (!opt)
10628c2ecf20Sopenharmony_ci		return -EINVAL;
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	q->loss_model = CLG_RANDOM;
10658c2ecf20Sopenharmony_ci	ret = netem_change(sch, opt, extack);
10668c2ecf20Sopenharmony_ci	if (ret)
10678c2ecf20Sopenharmony_ci		pr_info("netem: change failed\n");
10688c2ecf20Sopenharmony_ci	return ret;
10698c2ecf20Sopenharmony_ci}
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_cistatic void netem_destroy(struct Qdisc *sch)
10728c2ecf20Sopenharmony_ci{
10738c2ecf20Sopenharmony_ci	struct netem_sched_data *q = qdisc_priv(sch);
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci	qdisc_watchdog_cancel(&q->watchdog);
10768c2ecf20Sopenharmony_ci	if (q->qdisc)
10778c2ecf20Sopenharmony_ci		qdisc_put(q->qdisc);
10788c2ecf20Sopenharmony_ci	dist_free(q->delay_dist);
10798c2ecf20Sopenharmony_ci	dist_free(q->slot_dist);
10808c2ecf20Sopenharmony_ci}
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_cistatic int dump_loss_model(const struct netem_sched_data *q,
10838c2ecf20Sopenharmony_ci			   struct sk_buff *skb)
10848c2ecf20Sopenharmony_ci{
10858c2ecf20Sopenharmony_ci	struct nlattr *nest;
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	nest = nla_nest_start_noflag(skb, TCA_NETEM_LOSS);
10888c2ecf20Sopenharmony_ci	if (nest == NULL)
10898c2ecf20Sopenharmony_ci		goto nla_put_failure;
10908c2ecf20Sopenharmony_ci
10918c2ecf20Sopenharmony_ci	switch (q->loss_model) {
10928c2ecf20Sopenharmony_ci	case CLG_RANDOM:
10938c2ecf20Sopenharmony_ci		/* legacy loss model */
10948c2ecf20Sopenharmony_ci		nla_nest_cancel(skb, nest);
10958c2ecf20Sopenharmony_ci		return 0;	/* no data */
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	case CLG_4_STATES: {
10988c2ecf20Sopenharmony_ci		struct tc_netem_gimodel gi = {
10998c2ecf20Sopenharmony_ci			.p13 = q->clg.a1,
11008c2ecf20Sopenharmony_ci			.p31 = q->clg.a2,
11018c2ecf20Sopenharmony_ci			.p32 = q->clg.a3,
11028c2ecf20Sopenharmony_ci			.p14 = q->clg.a4,
11038c2ecf20Sopenharmony_ci			.p23 = q->clg.a5,
11048c2ecf20Sopenharmony_ci		};
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci		if (nla_put(skb, NETEM_LOSS_GI, sizeof(gi), &gi))
11078c2ecf20Sopenharmony_ci			goto nla_put_failure;
11088c2ecf20Sopenharmony_ci		break;
11098c2ecf20Sopenharmony_ci	}
11108c2ecf20Sopenharmony_ci	case CLG_GILB_ELL: {
11118c2ecf20Sopenharmony_ci		struct tc_netem_gemodel ge = {
11128c2ecf20Sopenharmony_ci			.p = q->clg.a1,
11138c2ecf20Sopenharmony_ci			.r = q->clg.a2,
11148c2ecf20Sopenharmony_ci			.h = q->clg.a3,
11158c2ecf20Sopenharmony_ci			.k1 = q->clg.a4,
11168c2ecf20Sopenharmony_ci		};
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci		if (nla_put(skb, NETEM_LOSS_GE, sizeof(ge), &ge))
11198c2ecf20Sopenharmony_ci			goto nla_put_failure;
11208c2ecf20Sopenharmony_ci		break;
11218c2ecf20Sopenharmony_ci	}
11228c2ecf20Sopenharmony_ci	}
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci	nla_nest_end(skb, nest);
11258c2ecf20Sopenharmony_ci	return 0;
11268c2ecf20Sopenharmony_ci
11278c2ecf20Sopenharmony_cinla_put_failure:
11288c2ecf20Sopenharmony_ci	nla_nest_cancel(skb, nest);
11298c2ecf20Sopenharmony_ci	return -1;
11308c2ecf20Sopenharmony_ci}
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_cistatic int netem_dump(struct Qdisc *sch, struct sk_buff *skb)
11338c2ecf20Sopenharmony_ci{
11348c2ecf20Sopenharmony_ci	const struct netem_sched_data *q = qdisc_priv(sch);
11358c2ecf20Sopenharmony_ci	struct nlattr *nla = (struct nlattr *) skb_tail_pointer(skb);
11368c2ecf20Sopenharmony_ci	struct tc_netem_qopt qopt;
11378c2ecf20Sopenharmony_ci	struct tc_netem_corr cor;
11388c2ecf20Sopenharmony_ci	struct tc_netem_reorder reorder;
11398c2ecf20Sopenharmony_ci	struct tc_netem_corrupt corrupt;
11408c2ecf20Sopenharmony_ci	struct tc_netem_rate rate;
11418c2ecf20Sopenharmony_ci	struct tc_netem_slot slot;
11428c2ecf20Sopenharmony_ci
11438c2ecf20Sopenharmony_ci	qopt.latency = min_t(psched_time_t, PSCHED_NS2TICKS(q->latency),
11448c2ecf20Sopenharmony_ci			     UINT_MAX);
11458c2ecf20Sopenharmony_ci	qopt.jitter = min_t(psched_time_t, PSCHED_NS2TICKS(q->jitter),
11468c2ecf20Sopenharmony_ci			    UINT_MAX);
11478c2ecf20Sopenharmony_ci	qopt.limit = q->limit;
11488c2ecf20Sopenharmony_ci	qopt.loss = q->loss;
11498c2ecf20Sopenharmony_ci	qopt.gap = q->gap;
11508c2ecf20Sopenharmony_ci	qopt.duplicate = q->duplicate;
11518c2ecf20Sopenharmony_ci	if (nla_put(skb, TCA_OPTIONS, sizeof(qopt), &qopt))
11528c2ecf20Sopenharmony_ci		goto nla_put_failure;
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	if (nla_put(skb, TCA_NETEM_LATENCY64, sizeof(q->latency), &q->latency))
11558c2ecf20Sopenharmony_ci		goto nla_put_failure;
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci	if (nla_put(skb, TCA_NETEM_JITTER64, sizeof(q->jitter), &q->jitter))
11588c2ecf20Sopenharmony_ci		goto nla_put_failure;
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_ci	cor.delay_corr = q->delay_cor.rho;
11618c2ecf20Sopenharmony_ci	cor.loss_corr = q->loss_cor.rho;
11628c2ecf20Sopenharmony_ci	cor.dup_corr = q->dup_cor.rho;
11638c2ecf20Sopenharmony_ci	if (nla_put(skb, TCA_NETEM_CORR, sizeof(cor), &cor))
11648c2ecf20Sopenharmony_ci		goto nla_put_failure;
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci	reorder.probability = q->reorder;
11678c2ecf20Sopenharmony_ci	reorder.correlation = q->reorder_cor.rho;
11688c2ecf20Sopenharmony_ci	if (nla_put(skb, TCA_NETEM_REORDER, sizeof(reorder), &reorder))
11698c2ecf20Sopenharmony_ci		goto nla_put_failure;
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci	corrupt.probability = q->corrupt;
11728c2ecf20Sopenharmony_ci	corrupt.correlation = q->corrupt_cor.rho;
11738c2ecf20Sopenharmony_ci	if (nla_put(skb, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt))
11748c2ecf20Sopenharmony_ci		goto nla_put_failure;
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci	if (q->rate >= (1ULL << 32)) {
11778c2ecf20Sopenharmony_ci		if (nla_put_u64_64bit(skb, TCA_NETEM_RATE64, q->rate,
11788c2ecf20Sopenharmony_ci				      TCA_NETEM_PAD))
11798c2ecf20Sopenharmony_ci			goto nla_put_failure;
11808c2ecf20Sopenharmony_ci		rate.rate = ~0U;
11818c2ecf20Sopenharmony_ci	} else {
11828c2ecf20Sopenharmony_ci		rate.rate = q->rate;
11838c2ecf20Sopenharmony_ci	}
11848c2ecf20Sopenharmony_ci	rate.packet_overhead = q->packet_overhead;
11858c2ecf20Sopenharmony_ci	rate.cell_size = q->cell_size;
11868c2ecf20Sopenharmony_ci	rate.cell_overhead = q->cell_overhead;
11878c2ecf20Sopenharmony_ci	if (nla_put(skb, TCA_NETEM_RATE, sizeof(rate), &rate))
11888c2ecf20Sopenharmony_ci		goto nla_put_failure;
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci	if (q->ecn && nla_put_u32(skb, TCA_NETEM_ECN, q->ecn))
11918c2ecf20Sopenharmony_ci		goto nla_put_failure;
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci	if (dump_loss_model(q, skb) != 0)
11948c2ecf20Sopenharmony_ci		goto nla_put_failure;
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_ci	if (q->slot_config.min_delay | q->slot_config.max_delay |
11978c2ecf20Sopenharmony_ci	    q->slot_config.dist_jitter) {
11988c2ecf20Sopenharmony_ci		slot = q->slot_config;
11998c2ecf20Sopenharmony_ci		if (slot.max_packets == INT_MAX)
12008c2ecf20Sopenharmony_ci			slot.max_packets = 0;
12018c2ecf20Sopenharmony_ci		if (slot.max_bytes == INT_MAX)
12028c2ecf20Sopenharmony_ci			slot.max_bytes = 0;
12038c2ecf20Sopenharmony_ci		if (nla_put(skb, TCA_NETEM_SLOT, sizeof(slot), &slot))
12048c2ecf20Sopenharmony_ci			goto nla_put_failure;
12058c2ecf20Sopenharmony_ci	}
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci	return nla_nest_end(skb, nla);
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_cinla_put_failure:
12108c2ecf20Sopenharmony_ci	nlmsg_trim(skb, nla);
12118c2ecf20Sopenharmony_ci	return -1;
12128c2ecf20Sopenharmony_ci}
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_cistatic int netem_dump_class(struct Qdisc *sch, unsigned long cl,
12158c2ecf20Sopenharmony_ci			  struct sk_buff *skb, struct tcmsg *tcm)
12168c2ecf20Sopenharmony_ci{
12178c2ecf20Sopenharmony_ci	struct netem_sched_data *q = qdisc_priv(sch);
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci	if (cl != 1 || !q->qdisc) 	/* only one class */
12208c2ecf20Sopenharmony_ci		return -ENOENT;
12218c2ecf20Sopenharmony_ci
12228c2ecf20Sopenharmony_ci	tcm->tcm_handle |= TC_H_MIN(1);
12238c2ecf20Sopenharmony_ci	tcm->tcm_info = q->qdisc->handle;
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci	return 0;
12268c2ecf20Sopenharmony_ci}
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_cistatic int netem_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
12298c2ecf20Sopenharmony_ci		     struct Qdisc **old, struct netlink_ext_ack *extack)
12308c2ecf20Sopenharmony_ci{
12318c2ecf20Sopenharmony_ci	struct netem_sched_data *q = qdisc_priv(sch);
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci	*old = qdisc_replace(sch, new, &q->qdisc);
12348c2ecf20Sopenharmony_ci	return 0;
12358c2ecf20Sopenharmony_ci}
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_cistatic struct Qdisc *netem_leaf(struct Qdisc *sch, unsigned long arg)
12388c2ecf20Sopenharmony_ci{
12398c2ecf20Sopenharmony_ci	struct netem_sched_data *q = qdisc_priv(sch);
12408c2ecf20Sopenharmony_ci	return q->qdisc;
12418c2ecf20Sopenharmony_ci}
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_cistatic unsigned long netem_find(struct Qdisc *sch, u32 classid)
12448c2ecf20Sopenharmony_ci{
12458c2ecf20Sopenharmony_ci	return 1;
12468c2ecf20Sopenharmony_ci}
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_cistatic void netem_walk(struct Qdisc *sch, struct qdisc_walker *walker)
12498c2ecf20Sopenharmony_ci{
12508c2ecf20Sopenharmony_ci	if (!walker->stop) {
12518c2ecf20Sopenharmony_ci		if (walker->count >= walker->skip)
12528c2ecf20Sopenharmony_ci			if (walker->fn(sch, 1, walker) < 0) {
12538c2ecf20Sopenharmony_ci				walker->stop = 1;
12548c2ecf20Sopenharmony_ci				return;
12558c2ecf20Sopenharmony_ci			}
12568c2ecf20Sopenharmony_ci		walker->count++;
12578c2ecf20Sopenharmony_ci	}
12588c2ecf20Sopenharmony_ci}
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_cistatic const struct Qdisc_class_ops netem_class_ops = {
12618c2ecf20Sopenharmony_ci	.graft		=	netem_graft,
12628c2ecf20Sopenharmony_ci	.leaf		=	netem_leaf,
12638c2ecf20Sopenharmony_ci	.find		=	netem_find,
12648c2ecf20Sopenharmony_ci	.walk		=	netem_walk,
12658c2ecf20Sopenharmony_ci	.dump		=	netem_dump_class,
12668c2ecf20Sopenharmony_ci};
12678c2ecf20Sopenharmony_ci
12688c2ecf20Sopenharmony_cistatic struct Qdisc_ops netem_qdisc_ops __read_mostly = {
12698c2ecf20Sopenharmony_ci	.id		=	"netem",
12708c2ecf20Sopenharmony_ci	.cl_ops		=	&netem_class_ops,
12718c2ecf20Sopenharmony_ci	.priv_size	=	sizeof(struct netem_sched_data),
12728c2ecf20Sopenharmony_ci	.enqueue	=	netem_enqueue,
12738c2ecf20Sopenharmony_ci	.dequeue	=	netem_dequeue,
12748c2ecf20Sopenharmony_ci	.peek		=	qdisc_peek_dequeued,
12758c2ecf20Sopenharmony_ci	.init		=	netem_init,
12768c2ecf20Sopenharmony_ci	.reset		=	netem_reset,
12778c2ecf20Sopenharmony_ci	.destroy	=	netem_destroy,
12788c2ecf20Sopenharmony_ci	.change		=	netem_change,
12798c2ecf20Sopenharmony_ci	.dump		=	netem_dump,
12808c2ecf20Sopenharmony_ci	.owner		=	THIS_MODULE,
12818c2ecf20Sopenharmony_ci};
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_cistatic int __init netem_module_init(void)
12858c2ecf20Sopenharmony_ci{
12868c2ecf20Sopenharmony_ci	pr_info("netem: version " VERSION "\n");
12878c2ecf20Sopenharmony_ci	return register_qdisc(&netem_qdisc_ops);
12888c2ecf20Sopenharmony_ci}
12898c2ecf20Sopenharmony_cistatic void __exit netem_module_exit(void)
12908c2ecf20Sopenharmony_ci{
12918c2ecf20Sopenharmony_ci	unregister_qdisc(&netem_qdisc_ops);
12928c2ecf20Sopenharmony_ci}
12938c2ecf20Sopenharmony_cimodule_init(netem_module_init)
12948c2ecf20Sopenharmony_cimodule_exit(netem_module_exit)
12958c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
1296