xref: /aosp_15_r20/external/libnl/lib/route/qdisc/netem.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
1*4dc78e53SAndroid Build Coastguard Worker /* SPDX-License-Identifier: LGPL-2.1-only */
2*4dc78e53SAndroid Build Coastguard Worker /*
3*4dc78e53SAndroid Build Coastguard Worker  * Copyright (c) 2003-2011 Thomas Graf <[email protected]>
4*4dc78e53SAndroid Build Coastguard Worker  */
5*4dc78e53SAndroid Build Coastguard Worker 
6*4dc78e53SAndroid Build Coastguard Worker /**
7*4dc78e53SAndroid Build Coastguard Worker  * @ingroup qdisc
8*4dc78e53SAndroid Build Coastguard Worker  * @defgroup qdisc_netem Network Emulator
9*4dc78e53SAndroid Build Coastguard Worker  * @brief
10*4dc78e53SAndroid Build Coastguard Worker  *
11*4dc78e53SAndroid Build Coastguard Worker  * For further documentation see http://linux-net.osdl.org/index.php/Netem
12*4dc78e53SAndroid Build Coastguard Worker  * @{
13*4dc78e53SAndroid Build Coastguard Worker  */
14*4dc78e53SAndroid Build Coastguard Worker 
15*4dc78e53SAndroid Build Coastguard Worker #include "nl-default.h"
16*4dc78e53SAndroid Build Coastguard Worker 
17*4dc78e53SAndroid Build Coastguard Worker #include <netlink/netlink.h>
18*4dc78e53SAndroid Build Coastguard Worker #include <netlink/utils.h>
19*4dc78e53SAndroid Build Coastguard Worker #include <netlink/route/qdisc.h>
20*4dc78e53SAndroid Build Coastguard Worker #include <netlink/route/qdisc/netem.h>
21*4dc78e53SAndroid Build Coastguard Worker 
22*4dc78e53SAndroid Build Coastguard Worker #include "tc-api.h"
23*4dc78e53SAndroid Build Coastguard Worker #include "nl-priv-dynamic-core/nl-core.h"
24*4dc78e53SAndroid Build Coastguard Worker 
25*4dc78e53SAndroid Build Coastguard Worker /** @cond SKIP */
26*4dc78e53SAndroid Build Coastguard Worker struct rtnl_netem_corr {
27*4dc78e53SAndroid Build Coastguard Worker 	uint32_t nmc_delay;
28*4dc78e53SAndroid Build Coastguard Worker 	uint32_t nmc_loss;
29*4dc78e53SAndroid Build Coastguard Worker 	uint32_t nmc_duplicate;
30*4dc78e53SAndroid Build Coastguard Worker };
31*4dc78e53SAndroid Build Coastguard Worker 
32*4dc78e53SAndroid Build Coastguard Worker struct rtnl_netem_reo {
33*4dc78e53SAndroid Build Coastguard Worker 	uint32_t nmro_probability;
34*4dc78e53SAndroid Build Coastguard Worker 	uint32_t nmro_correlation;
35*4dc78e53SAndroid Build Coastguard Worker };
36*4dc78e53SAndroid Build Coastguard Worker 
37*4dc78e53SAndroid Build Coastguard Worker struct rtnl_netem_crpt {
38*4dc78e53SAndroid Build Coastguard Worker 	uint32_t nmcr_probability;
39*4dc78e53SAndroid Build Coastguard Worker 	uint32_t nmcr_correlation;
40*4dc78e53SAndroid Build Coastguard Worker };
41*4dc78e53SAndroid Build Coastguard Worker 
42*4dc78e53SAndroid Build Coastguard Worker struct rtnl_netem_dist {
43*4dc78e53SAndroid Build Coastguard Worker 	int16_t *dist_data;
44*4dc78e53SAndroid Build Coastguard Worker 	size_t dist_size;
45*4dc78e53SAndroid Build Coastguard Worker };
46*4dc78e53SAndroid Build Coastguard Worker 
47*4dc78e53SAndroid Build Coastguard Worker struct rtnl_netem {
48*4dc78e53SAndroid Build Coastguard Worker 	uint32_t qnm_latency;
49*4dc78e53SAndroid Build Coastguard Worker 	uint32_t qnm_limit;
50*4dc78e53SAndroid Build Coastguard Worker 	uint32_t qnm_loss;
51*4dc78e53SAndroid Build Coastguard Worker 	uint32_t qnm_gap;
52*4dc78e53SAndroid Build Coastguard Worker 	uint32_t qnm_duplicate;
53*4dc78e53SAndroid Build Coastguard Worker 	uint32_t qnm_jitter;
54*4dc78e53SAndroid Build Coastguard Worker 	uint32_t qnm_mask;
55*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem_corr qnm_corr;
56*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem_reo qnm_ro;
57*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem_crpt qnm_crpt;
58*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem_dist qnm_dist;
59*4dc78e53SAndroid Build Coastguard Worker };
60*4dc78e53SAndroid Build Coastguard Worker 
61*4dc78e53SAndroid Build Coastguard Worker #define SCH_NETEM_ATTR_LATENCY		0x0001
62*4dc78e53SAndroid Build Coastguard Worker #define SCH_NETEM_ATTR_LIMIT		0x0002
63*4dc78e53SAndroid Build Coastguard Worker #define SCH_NETEM_ATTR_LOSS		0x0004
64*4dc78e53SAndroid Build Coastguard Worker #define SCH_NETEM_ATTR_GAP		0x0008
65*4dc78e53SAndroid Build Coastguard Worker #define SCH_NETEM_ATTR_DUPLICATE	0x0010
66*4dc78e53SAndroid Build Coastguard Worker #define SCH_NETEM_ATTR_JITTER		0x0020
67*4dc78e53SAndroid Build Coastguard Worker #define SCH_NETEM_ATTR_DELAY_CORR	0x0040
68*4dc78e53SAndroid Build Coastguard Worker #define SCH_NETEM_ATTR_LOSS_CORR	0x0080
69*4dc78e53SAndroid Build Coastguard Worker #define SCH_NETEM_ATTR_DUP_CORR		0x0100
70*4dc78e53SAndroid Build Coastguard Worker #define SCH_NETEM_ATTR_RO_PROB		0x0200
71*4dc78e53SAndroid Build Coastguard Worker #define SCH_NETEM_ATTR_RO_CORR		0x0400
72*4dc78e53SAndroid Build Coastguard Worker #define SCH_NETEM_ATTR_CORRUPT_PROB	0x0800
73*4dc78e53SAndroid Build Coastguard Worker #define SCH_NETEM_ATTR_CORRUPT_CORR	0x1000
74*4dc78e53SAndroid Build Coastguard Worker #define SCH_NETEM_ATTR_DIST		0x2000
75*4dc78e53SAndroid Build Coastguard Worker /** @endcond */
76*4dc78e53SAndroid Build Coastguard Worker 
77*4dc78e53SAndroid Build Coastguard Worker static struct nla_policy netem_policy[TCA_NETEM_MAX+1] = {
78*4dc78e53SAndroid Build Coastguard Worker 	[TCA_NETEM_CORR]	= { .minlen = sizeof(struct tc_netem_corr) },
79*4dc78e53SAndroid Build Coastguard Worker 	[TCA_NETEM_REORDER]	= { .minlen = sizeof(struct tc_netem_reorder) },
80*4dc78e53SAndroid Build Coastguard Worker 	[TCA_NETEM_CORRUPT]	= { .minlen = sizeof(struct tc_netem_corrupt) },
81*4dc78e53SAndroid Build Coastguard Worker };
82*4dc78e53SAndroid Build Coastguard Worker 
netem_msg_parser(struct rtnl_tc * tc,void * data)83*4dc78e53SAndroid Build Coastguard Worker static int netem_msg_parser(struct rtnl_tc *tc, void *data)
84*4dc78e53SAndroid Build Coastguard Worker {
85*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem = data;
86*4dc78e53SAndroid Build Coastguard Worker 	struct tc_netem_qopt *opts;
87*4dc78e53SAndroid Build Coastguard Worker 	int len, err = 0;
88*4dc78e53SAndroid Build Coastguard Worker 
89*4dc78e53SAndroid Build Coastguard Worker 	if (tc->tc_opts->d_size < sizeof(*opts))
90*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_INVAL;
91*4dc78e53SAndroid Build Coastguard Worker 
92*4dc78e53SAndroid Build Coastguard Worker 	opts = (struct tc_netem_qopt *) tc->tc_opts->d_data;
93*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_latency = opts->latency;
94*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_limit = opts->limit;
95*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_loss = opts->loss;
96*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_gap = opts->gap;
97*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_duplicate = opts->duplicate;
98*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_jitter = opts->jitter;
99*4dc78e53SAndroid Build Coastguard Worker 
100*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_mask = (SCH_NETEM_ATTR_LATENCY | SCH_NETEM_ATTR_LIMIT |
101*4dc78e53SAndroid Build Coastguard Worker 			   SCH_NETEM_ATTR_LOSS | SCH_NETEM_ATTR_GAP |
102*4dc78e53SAndroid Build Coastguard Worker 			   SCH_NETEM_ATTR_DUPLICATE | SCH_NETEM_ATTR_JITTER);
103*4dc78e53SAndroid Build Coastguard Worker 
104*4dc78e53SAndroid Build Coastguard Worker 	len = tc->tc_opts->d_size - sizeof(*opts);
105*4dc78e53SAndroid Build Coastguard Worker 
106*4dc78e53SAndroid Build Coastguard Worker 	if (len > 0) {
107*4dc78e53SAndroid Build Coastguard Worker 		struct nlattr *tb[TCA_NETEM_MAX+1];
108*4dc78e53SAndroid Build Coastguard Worker 
109*4dc78e53SAndroid Build Coastguard Worker 		err = nla_parse(tb, TCA_NETEM_MAX, (struct nlattr *)
110*4dc78e53SAndroid Build Coastguard Worker 				((char *) tc->tc_opts->d_data + sizeof(*opts)),
111*4dc78e53SAndroid Build Coastguard Worker 				len, netem_policy);
112*4dc78e53SAndroid Build Coastguard Worker 		if (err < 0) {
113*4dc78e53SAndroid Build Coastguard Worker 			free(netem);
114*4dc78e53SAndroid Build Coastguard Worker 			return err;
115*4dc78e53SAndroid Build Coastguard Worker 		}
116*4dc78e53SAndroid Build Coastguard Worker 
117*4dc78e53SAndroid Build Coastguard Worker 		if (tb[TCA_NETEM_CORR]) {
118*4dc78e53SAndroid Build Coastguard Worker 			struct tc_netem_corr cor;
119*4dc78e53SAndroid Build Coastguard Worker 
120*4dc78e53SAndroid Build Coastguard Worker 			nla_memcpy(&cor, tb[TCA_NETEM_CORR], sizeof(cor));
121*4dc78e53SAndroid Build Coastguard Worker 			netem->qnm_corr.nmc_delay = cor.delay_corr;
122*4dc78e53SAndroid Build Coastguard Worker 			netem->qnm_corr.nmc_loss = cor.loss_corr;
123*4dc78e53SAndroid Build Coastguard Worker 			netem->qnm_corr.nmc_duplicate = cor.dup_corr;
124*4dc78e53SAndroid Build Coastguard Worker 
125*4dc78e53SAndroid Build Coastguard Worker 			netem->qnm_mask |= (SCH_NETEM_ATTR_DELAY_CORR |
126*4dc78e53SAndroid Build Coastguard Worker 					    SCH_NETEM_ATTR_LOSS_CORR |
127*4dc78e53SAndroid Build Coastguard Worker 					SCH_NETEM_ATTR_DUP_CORR);
128*4dc78e53SAndroid Build Coastguard Worker 		}
129*4dc78e53SAndroid Build Coastguard Worker 
130*4dc78e53SAndroid Build Coastguard Worker 		if (tb[TCA_NETEM_REORDER]) {
131*4dc78e53SAndroid Build Coastguard Worker 			struct tc_netem_reorder ro;
132*4dc78e53SAndroid Build Coastguard Worker 
133*4dc78e53SAndroid Build Coastguard Worker 			nla_memcpy(&ro, tb[TCA_NETEM_REORDER], sizeof(ro));
134*4dc78e53SAndroid Build Coastguard Worker 			netem->qnm_ro.nmro_probability = ro.probability;
135*4dc78e53SAndroid Build Coastguard Worker 			netem->qnm_ro.nmro_correlation = ro.correlation;
136*4dc78e53SAndroid Build Coastguard Worker 
137*4dc78e53SAndroid Build Coastguard Worker 			netem->qnm_mask |= (SCH_NETEM_ATTR_RO_PROB |
138*4dc78e53SAndroid Build Coastguard Worker 					    SCH_NETEM_ATTR_RO_CORR);
139*4dc78e53SAndroid Build Coastguard Worker 		}
140*4dc78e53SAndroid Build Coastguard Worker 
141*4dc78e53SAndroid Build Coastguard Worker 		if (tb[TCA_NETEM_CORRUPT]) {
142*4dc78e53SAndroid Build Coastguard Worker 			struct tc_netem_corrupt corrupt;
143*4dc78e53SAndroid Build Coastguard Worker 
144*4dc78e53SAndroid Build Coastguard Worker 			nla_memcpy(&corrupt, tb[TCA_NETEM_CORRUPT], sizeof(corrupt));
145*4dc78e53SAndroid Build Coastguard Worker 			netem->qnm_crpt.nmcr_probability = corrupt.probability;
146*4dc78e53SAndroid Build Coastguard Worker 			netem->qnm_crpt.nmcr_correlation = corrupt.correlation;
147*4dc78e53SAndroid Build Coastguard Worker 
148*4dc78e53SAndroid Build Coastguard Worker 			netem->qnm_mask |= (SCH_NETEM_ATTR_CORRUPT_PROB |
149*4dc78e53SAndroid Build Coastguard Worker 						SCH_NETEM_ATTR_CORRUPT_CORR);
150*4dc78e53SAndroid Build Coastguard Worker 		}
151*4dc78e53SAndroid Build Coastguard Worker 
152*4dc78e53SAndroid Build Coastguard Worker 		/* sch_netem does not currently dump TCA_NETEM_DELAY_DIST */
153*4dc78e53SAndroid Build Coastguard Worker 		netem->qnm_dist.dist_data = NULL;
154*4dc78e53SAndroid Build Coastguard Worker 		netem->qnm_dist.dist_size = 0;
155*4dc78e53SAndroid Build Coastguard Worker 	}
156*4dc78e53SAndroid Build Coastguard Worker 
157*4dc78e53SAndroid Build Coastguard Worker 	return 0;
158*4dc78e53SAndroid Build Coastguard Worker }
159*4dc78e53SAndroid Build Coastguard Worker 
netem_free_data(struct rtnl_tc * tc,void * data)160*4dc78e53SAndroid Build Coastguard Worker static void netem_free_data(struct rtnl_tc *tc, void *data)
161*4dc78e53SAndroid Build Coastguard Worker {
162*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem = data;
163*4dc78e53SAndroid Build Coastguard Worker 
164*4dc78e53SAndroid Build Coastguard Worker 	if (!netem)
165*4dc78e53SAndroid Build Coastguard Worker 		return;
166*4dc78e53SAndroid Build Coastguard Worker 
167*4dc78e53SAndroid Build Coastguard Worker 	free(netem->qnm_dist.dist_data);
168*4dc78e53SAndroid Build Coastguard Worker }
169*4dc78e53SAndroid Build Coastguard Worker 
netem_dump_line(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)170*4dc78e53SAndroid Build Coastguard Worker static void netem_dump_line(struct rtnl_tc *tc, void *data,
171*4dc78e53SAndroid Build Coastguard Worker 			    struct nl_dump_params *p)
172*4dc78e53SAndroid Build Coastguard Worker {
173*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem = data;
174*4dc78e53SAndroid Build Coastguard Worker 
175*4dc78e53SAndroid Build Coastguard Worker 	if (netem) {
176*4dc78e53SAndroid Build Coastguard Worker 		if (netem->qnm_mask & SCH_NETEM_ATTR_LIMIT && netem->qnm_limit > 0)
177*4dc78e53SAndroid Build Coastguard Worker 			nl_dump(p, " limit %dpkts", netem->qnm_limit);
178*4dc78e53SAndroid Build Coastguard Worker 		else
179*4dc78e53SAndroid Build Coastguard Worker 			nl_dump(p, " no limit");
180*4dc78e53SAndroid Build Coastguard Worker 	}
181*4dc78e53SAndroid Build Coastguard Worker }
182*4dc78e53SAndroid Build Coastguard Worker 
netem_dump_details(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)183*4dc78e53SAndroid Build Coastguard Worker static void netem_dump_details(struct rtnl_tc *tc, void *data,
184*4dc78e53SAndroid Build Coastguard Worker                                struct nl_dump_params *p)
185*4dc78e53SAndroid Build Coastguard Worker {
186*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem = data;
187*4dc78e53SAndroid Build Coastguard Worker 	char buf[32];
188*4dc78e53SAndroid Build Coastguard Worker 
189*4dc78e53SAndroid Build Coastguard Worker 	if (netem) {
190*4dc78e53SAndroid Build Coastguard Worker 		if (netem->qnm_mask & SCH_NETEM_ATTR_LATENCY && netem->qnm_latency > 0) {
191*4dc78e53SAndroid Build Coastguard Worker 			nl_msec2str(nl_ticks2us(netem->qnm_latency) / 1000, buf, sizeof(buf));
192*4dc78e53SAndroid Build Coastguard Worker 			nl_dump(p, " latency %s", buf);
193*4dc78e53SAndroid Build Coastguard Worker 
194*4dc78e53SAndroid Build Coastguard Worker 			if (netem->qnm_mask & SCH_NETEM_ATTR_JITTER && netem->qnm_jitter > 0) {
195*4dc78e53SAndroid Build Coastguard Worker 				nl_msec2str(nl_ticks2us(netem->qnm_jitter) / 1000, buf, sizeof(buf));
196*4dc78e53SAndroid Build Coastguard Worker 				nl_dump(p, " jitter %s", buf);
197*4dc78e53SAndroid Build Coastguard Worker 
198*4dc78e53SAndroid Build Coastguard Worker 				if (netem->qnm_mask & SCH_NETEM_ATTR_DELAY_CORR && netem->qnm_corr.nmc_delay > 0)
199*4dc78e53SAndroid Build Coastguard Worker 					nl_dump(p, " %d", netem->qnm_corr.nmc_delay);
200*4dc78e53SAndroid Build Coastguard Worker 			}
201*4dc78e53SAndroid Build Coastguard Worker 		}
202*4dc78e53SAndroid Build Coastguard Worker 
203*4dc78e53SAndroid Build Coastguard Worker 		if (netem->qnm_mask & SCH_NETEM_ATTR_LOSS && netem->qnm_loss > 0) {
204*4dc78e53SAndroid Build Coastguard Worker 			nl_dump(p, " loss %d", netem->qnm_loss);
205*4dc78e53SAndroid Build Coastguard Worker 
206*4dc78e53SAndroid Build Coastguard Worker 			if (netem->qnm_mask & SCH_NETEM_ATTR_LOSS_CORR && netem->qnm_corr.nmc_loss > 0)
207*4dc78e53SAndroid Build Coastguard Worker 				nl_dump(p, " %d", netem->qnm_corr.nmc_loss);
208*4dc78e53SAndroid Build Coastguard Worker 		}
209*4dc78e53SAndroid Build Coastguard Worker 
210*4dc78e53SAndroid Build Coastguard Worker 		if (netem->qnm_mask & SCH_NETEM_ATTR_DUPLICATE && netem->qnm_duplicate > 0) {
211*4dc78e53SAndroid Build Coastguard Worker 			nl_dump(p, " duplicate %d", netem->qnm_duplicate);
212*4dc78e53SAndroid Build Coastguard Worker 
213*4dc78e53SAndroid Build Coastguard Worker 			if (netem->qnm_mask & SCH_NETEM_ATTR_DUP_CORR && netem->qnm_corr.nmc_duplicate > 0)
214*4dc78e53SAndroid Build Coastguard Worker 				nl_dump(p, " %d", netem->qnm_corr.nmc_duplicate);
215*4dc78e53SAndroid Build Coastguard Worker 		}
216*4dc78e53SAndroid Build Coastguard Worker 
217*4dc78e53SAndroid Build Coastguard Worker 		if (netem->qnm_mask & SCH_NETEM_ATTR_RO_PROB && netem->qnm_ro.nmro_probability > 0) {
218*4dc78e53SAndroid Build Coastguard Worker 			nl_dump(p, " reorder %d", netem->qnm_ro.nmro_probability);
219*4dc78e53SAndroid Build Coastguard Worker 
220*4dc78e53SAndroid Build Coastguard Worker 			if (netem->qnm_mask & SCH_NETEM_ATTR_RO_CORR && netem->qnm_ro.nmro_correlation > 0)
221*4dc78e53SAndroid Build Coastguard Worker 				nl_dump(p, " %d", netem->qnm_ro.nmro_correlation);
222*4dc78e53SAndroid Build Coastguard Worker 
223*4dc78e53SAndroid Build Coastguard Worker 			if (netem->qnm_mask & SCH_NETEM_ATTR_GAP && netem->qnm_gap > 0)
224*4dc78e53SAndroid Build Coastguard Worker 				nl_dump(p, " gap %d", netem->qnm_gap);
225*4dc78e53SAndroid Build Coastguard Worker 		}
226*4dc78e53SAndroid Build Coastguard Worker 
227*4dc78e53SAndroid Build Coastguard Worker 		if (netem->qnm_mask & SCH_NETEM_ATTR_CORRUPT_PROB && netem->qnm_crpt.nmcr_probability > 0) {
228*4dc78e53SAndroid Build Coastguard Worker 			nl_dump(p, " reorder %d", netem->qnm_crpt.nmcr_probability);
229*4dc78e53SAndroid Build Coastguard Worker 
230*4dc78e53SAndroid Build Coastguard Worker 			if (netem->qnm_mask & SCH_NETEM_ATTR_CORRUPT_CORR && netem->qnm_crpt.nmcr_correlation > 0)
231*4dc78e53SAndroid Build Coastguard Worker 				nl_dump(p, " %d", netem->qnm_crpt.nmcr_correlation);
232*4dc78e53SAndroid Build Coastguard Worker 		}
233*4dc78e53SAndroid Build Coastguard Worker 	}
234*4dc78e53SAndroid Build Coastguard Worker }
235*4dc78e53SAndroid Build Coastguard Worker 
netem_msg_fill_raw(struct rtnl_tc * tc,void * data,struct nl_msg * msg)236*4dc78e53SAndroid Build Coastguard Worker static int netem_msg_fill_raw(struct rtnl_tc *tc, void *data,
237*4dc78e53SAndroid Build Coastguard Worker                               struct nl_msg *msg)
238*4dc78e53SAndroid Build Coastguard Worker {
239*4dc78e53SAndroid Build Coastguard Worker 	int err = 0;
240*4dc78e53SAndroid Build Coastguard Worker 	struct tc_netem_qopt opts;
241*4dc78e53SAndroid Build Coastguard Worker 	struct tc_netem_corr cor;
242*4dc78e53SAndroid Build Coastguard Worker 	struct tc_netem_reorder reorder;
243*4dc78e53SAndroid Build Coastguard Worker 	struct tc_netem_corrupt corrupt;
244*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem = data;
245*4dc78e53SAndroid Build Coastguard Worker 
246*4dc78e53SAndroid Build Coastguard Worker 	unsigned char set_correlation = 0, set_reorder = 0;
247*4dc78e53SAndroid Build Coastguard Worker 	unsigned char set_corrupt = 0, set_dist = 0;
248*4dc78e53SAndroid Build Coastguard Worker 
249*4dc78e53SAndroid Build Coastguard Worker 	struct nlattr* head;
250*4dc78e53SAndroid Build Coastguard Worker 	struct nlattr* tail;
251*4dc78e53SAndroid Build Coastguard Worker 	int old_len;
252*4dc78e53SAndroid Build Coastguard Worker 
253*4dc78e53SAndroid Build Coastguard Worker 	if (!netem)
254*4dc78e53SAndroid Build Coastguard Worker 		BUG();
255*4dc78e53SAndroid Build Coastguard Worker 
256*4dc78e53SAndroid Build Coastguard Worker 	memset(&opts, 0, sizeof(opts));
257*4dc78e53SAndroid Build Coastguard Worker 	memset(&cor, 0, sizeof(cor));
258*4dc78e53SAndroid Build Coastguard Worker 	memset(&reorder, 0, sizeof(reorder));
259*4dc78e53SAndroid Build Coastguard Worker 	memset(&corrupt, 0, sizeof(corrupt));
260*4dc78e53SAndroid Build Coastguard Worker 
261*4dc78e53SAndroid Build Coastguard Worker 	msg->nm_nlh->nlmsg_flags |= NLM_F_REQUEST;
262*4dc78e53SAndroid Build Coastguard Worker 
263*4dc78e53SAndroid Build Coastguard Worker 	if (netem->qnm_ro.nmro_probability != 0) {
264*4dc78e53SAndroid Build Coastguard Worker 		if (netem->qnm_latency == 0)
265*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_MISSING_ATTR;
266*4dc78e53SAndroid Build Coastguard Worker 		if (netem->qnm_gap == 0)
267*4dc78e53SAndroid Build Coastguard Worker 			netem->qnm_gap = 1;
268*4dc78e53SAndroid Build Coastguard Worker 	} else if (netem->qnm_gap)
269*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_MISSING_ATTR;
270*4dc78e53SAndroid Build Coastguard Worker 
271*4dc78e53SAndroid Build Coastguard Worker 	if (netem->qnm_corr.nmc_delay != 0) {
272*4dc78e53SAndroid Build Coastguard Worker 		if (netem->qnm_latency == 0 || netem->qnm_jitter == 0)
273*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_MISSING_ATTR;
274*4dc78e53SAndroid Build Coastguard Worker 		set_correlation = 1;
275*4dc78e53SAndroid Build Coastguard Worker 	}
276*4dc78e53SAndroid Build Coastguard Worker 
277*4dc78e53SAndroid Build Coastguard Worker 	if (netem->qnm_corr.nmc_loss != 0) {
278*4dc78e53SAndroid Build Coastguard Worker 		if (netem->qnm_loss == 0)
279*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_MISSING_ATTR;
280*4dc78e53SAndroid Build Coastguard Worker 		set_correlation = 1;
281*4dc78e53SAndroid Build Coastguard Worker 	}
282*4dc78e53SAndroid Build Coastguard Worker 
283*4dc78e53SAndroid Build Coastguard Worker 	if (netem->qnm_corr.nmc_duplicate != 0) {
284*4dc78e53SAndroid Build Coastguard Worker 		if (netem->qnm_duplicate == 0)
285*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_MISSING_ATTR;
286*4dc78e53SAndroid Build Coastguard Worker 		set_correlation = 1;
287*4dc78e53SAndroid Build Coastguard Worker 	}
288*4dc78e53SAndroid Build Coastguard Worker 
289*4dc78e53SAndroid Build Coastguard Worker 	if (netem->qnm_ro.nmro_probability != 0)
290*4dc78e53SAndroid Build Coastguard Worker 		set_reorder = 1;
291*4dc78e53SAndroid Build Coastguard Worker 	else if (netem->qnm_ro.nmro_correlation != 0)
292*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_MISSING_ATTR;
293*4dc78e53SAndroid Build Coastguard Worker 
294*4dc78e53SAndroid Build Coastguard Worker 	if (netem->qnm_crpt.nmcr_probability != 0)
295*4dc78e53SAndroid Build Coastguard Worker 		set_corrupt = 1;
296*4dc78e53SAndroid Build Coastguard Worker 	else if (netem->qnm_crpt.nmcr_correlation != 0)
297*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_MISSING_ATTR;
298*4dc78e53SAndroid Build Coastguard Worker 
299*4dc78e53SAndroid Build Coastguard Worker 	if (netem->qnm_dist.dist_data && netem->qnm_dist.dist_size) {
300*4dc78e53SAndroid Build Coastguard Worker 		if (netem->qnm_latency == 0 || netem->qnm_jitter == 0)
301*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_MISSING_ATTR;
302*4dc78e53SAndroid Build Coastguard Worker 		else {
303*4dc78e53SAndroid Build Coastguard Worker 			/* Resize to accomodate the large distribution table */
304*4dc78e53SAndroid Build Coastguard Worker 			int new_msg_len = msg->nm_size + netem->qnm_dist.dist_size *
305*4dc78e53SAndroid Build Coastguard Worker 			                  sizeof(netem->qnm_dist.dist_data[0]);
306*4dc78e53SAndroid Build Coastguard Worker 			struct nlmsghdr *new_nlh = realloc(msg->nm_nlh, new_msg_len);
307*4dc78e53SAndroid Build Coastguard Worker 
308*4dc78e53SAndroid Build Coastguard Worker 			if (new_nlh == NULL)
309*4dc78e53SAndroid Build Coastguard Worker 				return -NLE_NOMEM;
310*4dc78e53SAndroid Build Coastguard Worker 			msg->nm_nlh = new_nlh;
311*4dc78e53SAndroid Build Coastguard Worker 			msg->nm_size = new_msg_len;
312*4dc78e53SAndroid Build Coastguard Worker 			set_dist = 1;
313*4dc78e53SAndroid Build Coastguard Worker 		}
314*4dc78e53SAndroid Build Coastguard Worker 	}
315*4dc78e53SAndroid Build Coastguard Worker 
316*4dc78e53SAndroid Build Coastguard Worker 	opts.latency = netem->qnm_latency;
317*4dc78e53SAndroid Build Coastguard Worker 	opts.limit = netem->qnm_limit ? netem->qnm_limit : 1000;
318*4dc78e53SAndroid Build Coastguard Worker 	opts.loss = netem->qnm_loss;
319*4dc78e53SAndroid Build Coastguard Worker 	opts.gap = netem->qnm_gap;
320*4dc78e53SAndroid Build Coastguard Worker 	opts.duplicate = netem->qnm_duplicate;
321*4dc78e53SAndroid Build Coastguard Worker 	opts.jitter = netem->qnm_jitter;
322*4dc78e53SAndroid Build Coastguard Worker 
323*4dc78e53SAndroid Build Coastguard Worker 	NLA_PUT(msg, TCA_OPTIONS, sizeof(opts), &opts);
324*4dc78e53SAndroid Build Coastguard Worker 
325*4dc78e53SAndroid Build Coastguard Worker 	if (set_correlation) {
326*4dc78e53SAndroid Build Coastguard Worker 		cor.delay_corr = netem->qnm_corr.nmc_delay;
327*4dc78e53SAndroid Build Coastguard Worker 		cor.loss_corr = netem->qnm_corr.nmc_loss;
328*4dc78e53SAndroid Build Coastguard Worker 		cor.dup_corr = netem->qnm_corr.nmc_duplicate;
329*4dc78e53SAndroid Build Coastguard Worker 
330*4dc78e53SAndroid Build Coastguard Worker 		NLA_PUT(msg, TCA_NETEM_CORR, sizeof(cor), &cor);
331*4dc78e53SAndroid Build Coastguard Worker 	}
332*4dc78e53SAndroid Build Coastguard Worker 
333*4dc78e53SAndroid Build Coastguard Worker 	if (set_reorder) {
334*4dc78e53SAndroid Build Coastguard Worker 		reorder.probability = netem->qnm_ro.nmro_probability;
335*4dc78e53SAndroid Build Coastguard Worker 		reorder.correlation = netem->qnm_ro.nmro_correlation;
336*4dc78e53SAndroid Build Coastguard Worker 
337*4dc78e53SAndroid Build Coastguard Worker 		NLA_PUT(msg, TCA_NETEM_REORDER, sizeof(reorder), &reorder);
338*4dc78e53SAndroid Build Coastguard Worker 	}
339*4dc78e53SAndroid Build Coastguard Worker 
340*4dc78e53SAndroid Build Coastguard Worker 	if (set_corrupt) {
341*4dc78e53SAndroid Build Coastguard Worker 		corrupt.probability = netem->qnm_crpt.nmcr_probability;
342*4dc78e53SAndroid Build Coastguard Worker 		corrupt.correlation = netem->qnm_crpt.nmcr_correlation;
343*4dc78e53SAndroid Build Coastguard Worker 
344*4dc78e53SAndroid Build Coastguard Worker 		NLA_PUT(msg, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt);
345*4dc78e53SAndroid Build Coastguard Worker 	}
346*4dc78e53SAndroid Build Coastguard Worker 
347*4dc78e53SAndroid Build Coastguard Worker 	if (set_dist) {
348*4dc78e53SAndroid Build Coastguard Worker 		NLA_PUT(msg, TCA_NETEM_DELAY_DIST,
349*4dc78e53SAndroid Build Coastguard Worker 		        netem->qnm_dist.dist_size * sizeof(netem->qnm_dist.dist_data[0]),
350*4dc78e53SAndroid Build Coastguard Worker 		        netem->qnm_dist.dist_data);
351*4dc78e53SAndroid Build Coastguard Worker 	}
352*4dc78e53SAndroid Build Coastguard Worker 
353*4dc78e53SAndroid Build Coastguard Worker 	/* Length specified in the TCA_OPTIONS section must span the entire
354*4dc78e53SAndroid Build Coastguard Worker 	 * remainder of the message. That's just the way that sch_netem expects it.
355*4dc78e53SAndroid Build Coastguard Worker 	 * Maybe there's a more succinct way to do this at a higher level.
356*4dc78e53SAndroid Build Coastguard Worker 	 */
357*4dc78e53SAndroid Build Coastguard Worker 	head = (struct nlattr *)(((char *) NLMSG_DATA(msg->nm_nlh)) +
358*4dc78e53SAndroid Build Coastguard Worker 	                         NLMSG_LENGTH(sizeof(struct tcmsg)) - NLMSG_ALIGNTO);
359*4dc78e53SAndroid Build Coastguard Worker 
360*4dc78e53SAndroid Build Coastguard Worker 	tail = (struct nlattr *)(((char *) (msg->nm_nlh)) +
361*4dc78e53SAndroid Build Coastguard Worker 	                         NLMSG_ALIGN(msg->nm_nlh->nlmsg_len));
362*4dc78e53SAndroid Build Coastguard Worker 
363*4dc78e53SAndroid Build Coastguard Worker 	old_len = head->nla_len;
364*4dc78e53SAndroid Build Coastguard Worker 	head->nla_len = (char *)tail - (char *)head;
365*4dc78e53SAndroid Build Coastguard Worker 	msg->nm_nlh->nlmsg_len += (head->nla_len - old_len);
366*4dc78e53SAndroid Build Coastguard Worker 
367*4dc78e53SAndroid Build Coastguard Worker 	return err;
368*4dc78e53SAndroid Build Coastguard Worker nla_put_failure:
369*4dc78e53SAndroid Build Coastguard Worker 	return -NLE_MSGSIZE;
370*4dc78e53SAndroid Build Coastguard Worker }
371*4dc78e53SAndroid Build Coastguard Worker 
372*4dc78e53SAndroid Build Coastguard Worker /**
373*4dc78e53SAndroid Build Coastguard Worker  * @name Queue Limit
374*4dc78e53SAndroid Build Coastguard Worker  * @{
375*4dc78e53SAndroid Build Coastguard Worker  */
376*4dc78e53SAndroid Build Coastguard Worker 
377*4dc78e53SAndroid Build Coastguard Worker /**
378*4dc78e53SAndroid Build Coastguard Worker  * Set limit of netem qdisc.
379*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		Netem qdisc to be modified.
380*4dc78e53SAndroid Build Coastguard Worker  * @arg limit		New limit in bytes.
381*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success or a negative error code.
382*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_netem_set_limit(struct rtnl_qdisc * qdisc,int limit)383*4dc78e53SAndroid Build Coastguard Worker void rtnl_netem_set_limit(struct rtnl_qdisc *qdisc, int limit)
384*4dc78e53SAndroid Build Coastguard Worker {
385*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem;
386*4dc78e53SAndroid Build Coastguard Worker 
387*4dc78e53SAndroid Build Coastguard Worker 	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
388*4dc78e53SAndroid Build Coastguard Worker 		BUG();
389*4dc78e53SAndroid Build Coastguard Worker 
390*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_limit = limit;
391*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_mask |= SCH_NETEM_ATTR_LIMIT;
392*4dc78e53SAndroid Build Coastguard Worker }
393*4dc78e53SAndroid Build Coastguard Worker 
394*4dc78e53SAndroid Build Coastguard Worker /**
395*4dc78e53SAndroid Build Coastguard Worker  * Get limit of netem qdisc.
396*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		Netem qdisc.
397*4dc78e53SAndroid Build Coastguard Worker  * @return Limit in bytes or a negative error code.
398*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_netem_get_limit(struct rtnl_qdisc * qdisc)399*4dc78e53SAndroid Build Coastguard Worker int rtnl_netem_get_limit(struct rtnl_qdisc *qdisc)
400*4dc78e53SAndroid Build Coastguard Worker {
401*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem;
402*4dc78e53SAndroid Build Coastguard Worker 
403*4dc78e53SAndroid Build Coastguard Worker 	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
404*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
405*4dc78e53SAndroid Build Coastguard Worker 
406*4dc78e53SAndroid Build Coastguard Worker 	if (netem->qnm_mask & SCH_NETEM_ATTR_LIMIT)
407*4dc78e53SAndroid Build Coastguard Worker 		return netem->qnm_limit;
408*4dc78e53SAndroid Build Coastguard Worker 	else
409*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOATTR;
410*4dc78e53SAndroid Build Coastguard Worker }
411*4dc78e53SAndroid Build Coastguard Worker 
412*4dc78e53SAndroid Build Coastguard Worker /** @} */
413*4dc78e53SAndroid Build Coastguard Worker 
414*4dc78e53SAndroid Build Coastguard Worker /**
415*4dc78e53SAndroid Build Coastguard Worker  * @name Packet Re-ordering
416*4dc78e53SAndroid Build Coastguard Worker  * @{
417*4dc78e53SAndroid Build Coastguard Worker  */
418*4dc78e53SAndroid Build Coastguard Worker 
419*4dc78e53SAndroid Build Coastguard Worker /**
420*4dc78e53SAndroid Build Coastguard Worker  * Set re-ordering gap of netem qdisc.
421*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		Netem qdisc to be modified.
422*4dc78e53SAndroid Build Coastguard Worker  * @arg gap		New gap in number of packets.
423*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success or a negative error code.
424*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_netem_set_gap(struct rtnl_qdisc * qdisc,int gap)425*4dc78e53SAndroid Build Coastguard Worker void rtnl_netem_set_gap(struct rtnl_qdisc *qdisc, int gap)
426*4dc78e53SAndroid Build Coastguard Worker {
427*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem;
428*4dc78e53SAndroid Build Coastguard Worker 
429*4dc78e53SAndroid Build Coastguard Worker 	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
430*4dc78e53SAndroid Build Coastguard Worker 		BUG();
431*4dc78e53SAndroid Build Coastguard Worker 
432*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_gap = gap;
433*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_mask |= SCH_NETEM_ATTR_GAP;
434*4dc78e53SAndroid Build Coastguard Worker }
435*4dc78e53SAndroid Build Coastguard Worker 
436*4dc78e53SAndroid Build Coastguard Worker /**
437*4dc78e53SAndroid Build Coastguard Worker  * Get re-ordering gap of netem qdisc.
438*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		Netem qdisc.
439*4dc78e53SAndroid Build Coastguard Worker  * @return Re-ordering gap in packets or a negative error code.
440*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_netem_get_gap(struct rtnl_qdisc * qdisc)441*4dc78e53SAndroid Build Coastguard Worker int rtnl_netem_get_gap(struct rtnl_qdisc *qdisc)
442*4dc78e53SAndroid Build Coastguard Worker {
443*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem;
444*4dc78e53SAndroid Build Coastguard Worker 
445*4dc78e53SAndroid Build Coastguard Worker 	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
446*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
447*4dc78e53SAndroid Build Coastguard Worker 
448*4dc78e53SAndroid Build Coastguard Worker 	if (netem->qnm_mask & SCH_NETEM_ATTR_GAP)
449*4dc78e53SAndroid Build Coastguard Worker 		return netem->qnm_gap;
450*4dc78e53SAndroid Build Coastguard Worker 	else
451*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOATTR;
452*4dc78e53SAndroid Build Coastguard Worker }
453*4dc78e53SAndroid Build Coastguard Worker 
454*4dc78e53SAndroid Build Coastguard Worker /**
455*4dc78e53SAndroid Build Coastguard Worker  * Set re-ordering probability of netem qdisc.
456*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		Netem qdisc to be modified.
457*4dc78e53SAndroid Build Coastguard Worker  * @arg prob		New re-ordering probability.
458*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success or a negative error code.
459*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_netem_set_reorder_probability(struct rtnl_qdisc * qdisc,int prob)460*4dc78e53SAndroid Build Coastguard Worker void rtnl_netem_set_reorder_probability(struct rtnl_qdisc *qdisc, int prob)
461*4dc78e53SAndroid Build Coastguard Worker {
462*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem;
463*4dc78e53SAndroid Build Coastguard Worker 
464*4dc78e53SAndroid Build Coastguard Worker 	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
465*4dc78e53SAndroid Build Coastguard Worker 		BUG();
466*4dc78e53SAndroid Build Coastguard Worker 
467*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_ro.nmro_probability = prob;
468*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_mask |= SCH_NETEM_ATTR_RO_PROB;
469*4dc78e53SAndroid Build Coastguard Worker }
470*4dc78e53SAndroid Build Coastguard Worker 
471*4dc78e53SAndroid Build Coastguard Worker /**
472*4dc78e53SAndroid Build Coastguard Worker  * Get re-ordering probability of netem qdisc.
473*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		Netem qdisc.
474*4dc78e53SAndroid Build Coastguard Worker  * @return Re-ordering probability or a negative error code.
475*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_netem_get_reorder_probability(struct rtnl_qdisc * qdisc)476*4dc78e53SAndroid Build Coastguard Worker int rtnl_netem_get_reorder_probability(struct rtnl_qdisc *qdisc)
477*4dc78e53SAndroid Build Coastguard Worker {
478*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem;
479*4dc78e53SAndroid Build Coastguard Worker 
480*4dc78e53SAndroid Build Coastguard Worker 	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
481*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
482*4dc78e53SAndroid Build Coastguard Worker 
483*4dc78e53SAndroid Build Coastguard Worker 	if (netem->qnm_mask & SCH_NETEM_ATTR_RO_PROB)
484*4dc78e53SAndroid Build Coastguard Worker 		return netem->qnm_ro.nmro_probability;
485*4dc78e53SAndroid Build Coastguard Worker 	else
486*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOATTR;
487*4dc78e53SAndroid Build Coastguard Worker }
488*4dc78e53SAndroid Build Coastguard Worker 
489*4dc78e53SAndroid Build Coastguard Worker /**
490*4dc78e53SAndroid Build Coastguard Worker  * Set re-order correlation probability of netem qdisc.
491*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		Netem qdisc to be modified.
492*4dc78e53SAndroid Build Coastguard Worker  * @arg prob		New re-ordering correlation probability.
493*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success or a negative error code.
494*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_netem_set_reorder_correlation(struct rtnl_qdisc * qdisc,int prob)495*4dc78e53SAndroid Build Coastguard Worker void rtnl_netem_set_reorder_correlation(struct rtnl_qdisc *qdisc, int prob)
496*4dc78e53SAndroid Build Coastguard Worker {
497*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem;
498*4dc78e53SAndroid Build Coastguard Worker 
499*4dc78e53SAndroid Build Coastguard Worker 	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
500*4dc78e53SAndroid Build Coastguard Worker 		BUG();
501*4dc78e53SAndroid Build Coastguard Worker 
502*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_ro.nmro_correlation = prob;
503*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_mask |= SCH_NETEM_ATTR_RO_CORR;
504*4dc78e53SAndroid Build Coastguard Worker }
505*4dc78e53SAndroid Build Coastguard Worker 
506*4dc78e53SAndroid Build Coastguard Worker /**
507*4dc78e53SAndroid Build Coastguard Worker  * Get re-ordering correlation probability of netem qdisc.
508*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		Netem qdisc.
509*4dc78e53SAndroid Build Coastguard Worker  * @return Re-ordering correlation probability or a negative error code.
510*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_netem_get_reorder_correlation(struct rtnl_qdisc * qdisc)511*4dc78e53SAndroid Build Coastguard Worker int rtnl_netem_get_reorder_correlation(struct rtnl_qdisc *qdisc)
512*4dc78e53SAndroid Build Coastguard Worker {
513*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem;
514*4dc78e53SAndroid Build Coastguard Worker 
515*4dc78e53SAndroid Build Coastguard Worker 	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
516*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
517*4dc78e53SAndroid Build Coastguard Worker 
518*4dc78e53SAndroid Build Coastguard Worker 	if (netem->qnm_mask & SCH_NETEM_ATTR_RO_CORR)
519*4dc78e53SAndroid Build Coastguard Worker 		return netem->qnm_ro.nmro_correlation;
520*4dc78e53SAndroid Build Coastguard Worker 	else
521*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOATTR;
522*4dc78e53SAndroid Build Coastguard Worker }
523*4dc78e53SAndroid Build Coastguard Worker 
524*4dc78e53SAndroid Build Coastguard Worker /** @} */
525*4dc78e53SAndroid Build Coastguard Worker 
526*4dc78e53SAndroid Build Coastguard Worker /**
527*4dc78e53SAndroid Build Coastguard Worker  * @name Corruption
528*4dc78e53SAndroid Build Coastguard Worker  * @{
529*4dc78e53SAndroid Build Coastguard Worker  */
530*4dc78e53SAndroid Build Coastguard Worker 
531*4dc78e53SAndroid Build Coastguard Worker /**
532*4dc78e53SAndroid Build Coastguard Worker  * Set corruption probability of netem qdisc.
533*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		Netem qdisc to be modified.
534*4dc78e53SAndroid Build Coastguard Worker  * @arg prob		New corruption probability.
535*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success or a negative error code.
536*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_netem_set_corruption_probability(struct rtnl_qdisc * qdisc,int prob)537*4dc78e53SAndroid Build Coastguard Worker void rtnl_netem_set_corruption_probability(struct rtnl_qdisc *qdisc, int prob)
538*4dc78e53SAndroid Build Coastguard Worker {
539*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem;
540*4dc78e53SAndroid Build Coastguard Worker 
541*4dc78e53SAndroid Build Coastguard Worker 	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
542*4dc78e53SAndroid Build Coastguard Worker 		BUG();
543*4dc78e53SAndroid Build Coastguard Worker 
544*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_crpt.nmcr_probability = prob;
545*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_mask |= SCH_NETEM_ATTR_CORRUPT_PROB;
546*4dc78e53SAndroid Build Coastguard Worker }
547*4dc78e53SAndroid Build Coastguard Worker 
548*4dc78e53SAndroid Build Coastguard Worker /**
549*4dc78e53SAndroid Build Coastguard Worker  * Get corruption probability of netem qdisc.
550*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		Netem qdisc.
551*4dc78e53SAndroid Build Coastguard Worker  * @return Corruption probability or a negative error code.
552*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_netem_get_corruption_probability(struct rtnl_qdisc * qdisc)553*4dc78e53SAndroid Build Coastguard Worker int rtnl_netem_get_corruption_probability(struct rtnl_qdisc *qdisc)
554*4dc78e53SAndroid Build Coastguard Worker {
555*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem;
556*4dc78e53SAndroid Build Coastguard Worker 
557*4dc78e53SAndroid Build Coastguard Worker 	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
558*4dc78e53SAndroid Build Coastguard Worker 		BUG();
559*4dc78e53SAndroid Build Coastguard Worker 
560*4dc78e53SAndroid Build Coastguard Worker 	if (netem->qnm_mask & SCH_NETEM_ATTR_CORRUPT_PROB)
561*4dc78e53SAndroid Build Coastguard Worker 		return netem->qnm_crpt.nmcr_probability;
562*4dc78e53SAndroid Build Coastguard Worker 	else
563*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOATTR;
564*4dc78e53SAndroid Build Coastguard Worker }
565*4dc78e53SAndroid Build Coastguard Worker 
566*4dc78e53SAndroid Build Coastguard Worker /**
567*4dc78e53SAndroid Build Coastguard Worker  * Set corruption correlation probability of netem qdisc.
568*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		Netem qdisc to be modified.
569*4dc78e53SAndroid Build Coastguard Worker  * @arg prob		New corruption correlation probability.
570*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success or a negative error code.
571*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_netem_set_corruption_correlation(struct rtnl_qdisc * qdisc,int prob)572*4dc78e53SAndroid Build Coastguard Worker void rtnl_netem_set_corruption_correlation(struct rtnl_qdisc *qdisc, int prob)
573*4dc78e53SAndroid Build Coastguard Worker {
574*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem;
575*4dc78e53SAndroid Build Coastguard Worker 
576*4dc78e53SAndroid Build Coastguard Worker 	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
577*4dc78e53SAndroid Build Coastguard Worker 		BUG();
578*4dc78e53SAndroid Build Coastguard Worker 
579*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_crpt.nmcr_correlation = prob;
580*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_mask |= SCH_NETEM_ATTR_CORRUPT_CORR;
581*4dc78e53SAndroid Build Coastguard Worker }
582*4dc78e53SAndroid Build Coastguard Worker 
583*4dc78e53SAndroid Build Coastguard Worker /**
584*4dc78e53SAndroid Build Coastguard Worker  * Get corruption correlation probability of netem qdisc.
585*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		Netem qdisc.
586*4dc78e53SAndroid Build Coastguard Worker  * @return Corruption correlation probability or a negative error code.
587*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_netem_get_corruption_correlation(struct rtnl_qdisc * qdisc)588*4dc78e53SAndroid Build Coastguard Worker int rtnl_netem_get_corruption_correlation(struct rtnl_qdisc *qdisc)
589*4dc78e53SAndroid Build Coastguard Worker {
590*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem;
591*4dc78e53SAndroid Build Coastguard Worker 
592*4dc78e53SAndroid Build Coastguard Worker 	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
593*4dc78e53SAndroid Build Coastguard Worker 		BUG();
594*4dc78e53SAndroid Build Coastguard Worker 
595*4dc78e53SAndroid Build Coastguard Worker 	if (netem->qnm_mask & SCH_NETEM_ATTR_CORRUPT_CORR)
596*4dc78e53SAndroid Build Coastguard Worker 		return netem->qnm_crpt.nmcr_correlation;
597*4dc78e53SAndroid Build Coastguard Worker 	else
598*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOATTR;
599*4dc78e53SAndroid Build Coastguard Worker }
600*4dc78e53SAndroid Build Coastguard Worker 
601*4dc78e53SAndroid Build Coastguard Worker /** @} */
602*4dc78e53SAndroid Build Coastguard Worker 
603*4dc78e53SAndroid Build Coastguard Worker /**
604*4dc78e53SAndroid Build Coastguard Worker  * @name Packet Loss
605*4dc78e53SAndroid Build Coastguard Worker  * @{
606*4dc78e53SAndroid Build Coastguard Worker  */
607*4dc78e53SAndroid Build Coastguard Worker 
608*4dc78e53SAndroid Build Coastguard Worker /**
609*4dc78e53SAndroid Build Coastguard Worker  * Set packet loss probability of netem qdisc.
610*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		Netem qdisc to be modified.
611*4dc78e53SAndroid Build Coastguard Worker  * @arg prob		New packet loss probability.
612*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success or a negative error code.
613*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_netem_set_loss(struct rtnl_qdisc * qdisc,int prob)614*4dc78e53SAndroid Build Coastguard Worker void rtnl_netem_set_loss(struct rtnl_qdisc *qdisc, int prob)
615*4dc78e53SAndroid Build Coastguard Worker {
616*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem;
617*4dc78e53SAndroid Build Coastguard Worker 
618*4dc78e53SAndroid Build Coastguard Worker 	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
619*4dc78e53SAndroid Build Coastguard Worker 		BUG();
620*4dc78e53SAndroid Build Coastguard Worker 
621*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_loss = prob;
622*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_mask |= SCH_NETEM_ATTR_LOSS;
623*4dc78e53SAndroid Build Coastguard Worker }
624*4dc78e53SAndroid Build Coastguard Worker 
625*4dc78e53SAndroid Build Coastguard Worker /**
626*4dc78e53SAndroid Build Coastguard Worker  * Get packet loss probability of netem qdisc.
627*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		Netem qdisc.
628*4dc78e53SAndroid Build Coastguard Worker  * @return Packet loss probability or a negative error code.
629*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_netem_get_loss(struct rtnl_qdisc * qdisc)630*4dc78e53SAndroid Build Coastguard Worker int rtnl_netem_get_loss(struct rtnl_qdisc *qdisc)
631*4dc78e53SAndroid Build Coastguard Worker {
632*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem;
633*4dc78e53SAndroid Build Coastguard Worker 
634*4dc78e53SAndroid Build Coastguard Worker 	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
635*4dc78e53SAndroid Build Coastguard Worker 		BUG();
636*4dc78e53SAndroid Build Coastguard Worker 
637*4dc78e53SAndroid Build Coastguard Worker 	if (netem->qnm_mask & SCH_NETEM_ATTR_LOSS)
638*4dc78e53SAndroid Build Coastguard Worker 		return netem->qnm_loss;
639*4dc78e53SAndroid Build Coastguard Worker 	else
640*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOATTR;
641*4dc78e53SAndroid Build Coastguard Worker }
642*4dc78e53SAndroid Build Coastguard Worker 
643*4dc78e53SAndroid Build Coastguard Worker /**
644*4dc78e53SAndroid Build Coastguard Worker  * Set packet loss correlation probability of netem qdisc.
645*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		Netem qdisc to be modified.
646*4dc78e53SAndroid Build Coastguard Worker  * @arg prob	New packet loss correlation.
647*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success or a negative error code.
648*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_netem_set_loss_correlation(struct rtnl_qdisc * qdisc,int prob)649*4dc78e53SAndroid Build Coastguard Worker void rtnl_netem_set_loss_correlation(struct rtnl_qdisc *qdisc, int prob)
650*4dc78e53SAndroid Build Coastguard Worker {
651*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem;
652*4dc78e53SAndroid Build Coastguard Worker 
653*4dc78e53SAndroid Build Coastguard Worker 	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
654*4dc78e53SAndroid Build Coastguard Worker 		BUG();
655*4dc78e53SAndroid Build Coastguard Worker 
656*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_corr.nmc_loss = prob;
657*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_mask |= SCH_NETEM_ATTR_LOSS_CORR;
658*4dc78e53SAndroid Build Coastguard Worker }
659*4dc78e53SAndroid Build Coastguard Worker 
660*4dc78e53SAndroid Build Coastguard Worker /**
661*4dc78e53SAndroid Build Coastguard Worker  * Get packet loss correlation probability of netem qdisc.
662*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		Netem qdisc.
663*4dc78e53SAndroid Build Coastguard Worker  * @return Packet loss correlation probability or a negative error code.
664*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_netem_get_loss_correlation(struct rtnl_qdisc * qdisc)665*4dc78e53SAndroid Build Coastguard Worker int rtnl_netem_get_loss_correlation(struct rtnl_qdisc *qdisc)
666*4dc78e53SAndroid Build Coastguard Worker {
667*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem;
668*4dc78e53SAndroid Build Coastguard Worker 
669*4dc78e53SAndroid Build Coastguard Worker 	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
670*4dc78e53SAndroid Build Coastguard Worker 		BUG();
671*4dc78e53SAndroid Build Coastguard Worker 
672*4dc78e53SAndroid Build Coastguard Worker 	if (netem->qnm_mask & SCH_NETEM_ATTR_LOSS_CORR)
673*4dc78e53SAndroid Build Coastguard Worker 		return netem->qnm_corr.nmc_loss;
674*4dc78e53SAndroid Build Coastguard Worker 	else
675*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOATTR;
676*4dc78e53SAndroid Build Coastguard Worker }
677*4dc78e53SAndroid Build Coastguard Worker 
678*4dc78e53SAndroid Build Coastguard Worker /** @} */
679*4dc78e53SAndroid Build Coastguard Worker 
680*4dc78e53SAndroid Build Coastguard Worker /**
681*4dc78e53SAndroid Build Coastguard Worker  * @name Packet Duplication
682*4dc78e53SAndroid Build Coastguard Worker  * @{
683*4dc78e53SAndroid Build Coastguard Worker  */
684*4dc78e53SAndroid Build Coastguard Worker 
685*4dc78e53SAndroid Build Coastguard Worker /**
686*4dc78e53SAndroid Build Coastguard Worker  * Set packet duplication probability of netem qdisc.
687*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		Netem qdisc to be modified.
688*4dc78e53SAndroid Build Coastguard Worker  * @arg prob	New packet duplication probability.
689*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success or a negative error code.
690*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_netem_set_duplicate(struct rtnl_qdisc * qdisc,int prob)691*4dc78e53SAndroid Build Coastguard Worker void rtnl_netem_set_duplicate(struct rtnl_qdisc *qdisc, int prob)
692*4dc78e53SAndroid Build Coastguard Worker {
693*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem;
694*4dc78e53SAndroid Build Coastguard Worker 
695*4dc78e53SAndroid Build Coastguard Worker 	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
696*4dc78e53SAndroid Build Coastguard Worker 		BUG();
697*4dc78e53SAndroid Build Coastguard Worker 
698*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_duplicate = prob;
699*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_mask |= SCH_NETEM_ATTR_DUPLICATE;
700*4dc78e53SAndroid Build Coastguard Worker }
701*4dc78e53SAndroid Build Coastguard Worker 
702*4dc78e53SAndroid Build Coastguard Worker /**
703*4dc78e53SAndroid Build Coastguard Worker  * Get packet duplication probability of netem qdisc.
704*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		Netem qdisc.
705*4dc78e53SAndroid Build Coastguard Worker  * @return Packet duplication probability or a negative error code.
706*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_netem_get_duplicate(struct rtnl_qdisc * qdisc)707*4dc78e53SAndroid Build Coastguard Worker int rtnl_netem_get_duplicate(struct rtnl_qdisc *qdisc)
708*4dc78e53SAndroid Build Coastguard Worker {
709*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem;
710*4dc78e53SAndroid Build Coastguard Worker 
711*4dc78e53SAndroid Build Coastguard Worker 	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
712*4dc78e53SAndroid Build Coastguard Worker 		BUG();
713*4dc78e53SAndroid Build Coastguard Worker 
714*4dc78e53SAndroid Build Coastguard Worker 	if (netem->qnm_mask & SCH_NETEM_ATTR_DUPLICATE)
715*4dc78e53SAndroid Build Coastguard Worker 		return netem->qnm_duplicate;
716*4dc78e53SAndroid Build Coastguard Worker 	else
717*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOATTR;
718*4dc78e53SAndroid Build Coastguard Worker }
719*4dc78e53SAndroid Build Coastguard Worker 
720*4dc78e53SAndroid Build Coastguard Worker /**
721*4dc78e53SAndroid Build Coastguard Worker  * Set packet duplication correlation probability of netem qdisc.
722*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		Netem qdisc to be modified.
723*4dc78e53SAndroid Build Coastguard Worker  * @arg prob		New packet duplication correlation probability.
724*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success or a negative error code.
725*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_netem_set_duplicate_correlation(struct rtnl_qdisc * qdisc,int prob)726*4dc78e53SAndroid Build Coastguard Worker void rtnl_netem_set_duplicate_correlation(struct rtnl_qdisc *qdisc, int prob)
727*4dc78e53SAndroid Build Coastguard Worker {
728*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem;
729*4dc78e53SAndroid Build Coastguard Worker 
730*4dc78e53SAndroid Build Coastguard Worker 	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
731*4dc78e53SAndroid Build Coastguard Worker 		BUG();
732*4dc78e53SAndroid Build Coastguard Worker 
733*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_corr.nmc_duplicate = prob;
734*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_mask |= SCH_NETEM_ATTR_DUP_CORR;
735*4dc78e53SAndroid Build Coastguard Worker }
736*4dc78e53SAndroid Build Coastguard Worker 
737*4dc78e53SAndroid Build Coastguard Worker /**
738*4dc78e53SAndroid Build Coastguard Worker  * Get packet duplication correlation probability of netem qdisc.
739*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		Netem qdisc.
740*4dc78e53SAndroid Build Coastguard Worker  * @return Packet duplication correlation probability or a negative error code.
741*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_netem_get_duplicate_correlation(struct rtnl_qdisc * qdisc)742*4dc78e53SAndroid Build Coastguard Worker int rtnl_netem_get_duplicate_correlation(struct rtnl_qdisc *qdisc)
743*4dc78e53SAndroid Build Coastguard Worker {
744*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem;
745*4dc78e53SAndroid Build Coastguard Worker 
746*4dc78e53SAndroid Build Coastguard Worker 	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
747*4dc78e53SAndroid Build Coastguard Worker 		BUG();
748*4dc78e53SAndroid Build Coastguard Worker 
749*4dc78e53SAndroid Build Coastguard Worker 	if (netem->qnm_mask & SCH_NETEM_ATTR_DUP_CORR)
750*4dc78e53SAndroid Build Coastguard Worker 		return netem->qnm_corr.nmc_duplicate;
751*4dc78e53SAndroid Build Coastguard Worker 	else
752*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOATTR;
753*4dc78e53SAndroid Build Coastguard Worker }
754*4dc78e53SAndroid Build Coastguard Worker 
755*4dc78e53SAndroid Build Coastguard Worker /** @} */
756*4dc78e53SAndroid Build Coastguard Worker 
757*4dc78e53SAndroid Build Coastguard Worker /**
758*4dc78e53SAndroid Build Coastguard Worker  * @name Packet Delay
759*4dc78e53SAndroid Build Coastguard Worker  * @{
760*4dc78e53SAndroid Build Coastguard Worker  */
761*4dc78e53SAndroid Build Coastguard Worker 
762*4dc78e53SAndroid Build Coastguard Worker /**
763*4dc78e53SAndroid Build Coastguard Worker  * Set packet delay of netem qdisc.
764*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		Netem qdisc to be modified.
765*4dc78e53SAndroid Build Coastguard Worker  * @arg delay		New packet delay in micro seconds.
766*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success or a negative error code.
767*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_netem_set_delay(struct rtnl_qdisc * qdisc,int delay)768*4dc78e53SAndroid Build Coastguard Worker void rtnl_netem_set_delay(struct rtnl_qdisc *qdisc, int delay)
769*4dc78e53SAndroid Build Coastguard Worker {
770*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem;
771*4dc78e53SAndroid Build Coastguard Worker 
772*4dc78e53SAndroid Build Coastguard Worker 	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
773*4dc78e53SAndroid Build Coastguard Worker 		BUG();
774*4dc78e53SAndroid Build Coastguard Worker 
775*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_latency = nl_us2ticks(delay);
776*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_mask |= SCH_NETEM_ATTR_LATENCY;
777*4dc78e53SAndroid Build Coastguard Worker }
778*4dc78e53SAndroid Build Coastguard Worker 
779*4dc78e53SAndroid Build Coastguard Worker /**
780*4dc78e53SAndroid Build Coastguard Worker  * Get packet delay of netem qdisc.
781*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		Netem qdisc.
782*4dc78e53SAndroid Build Coastguard Worker  * @return Packet delay in micro seconds or a negative error code.
783*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_netem_get_delay(struct rtnl_qdisc * qdisc)784*4dc78e53SAndroid Build Coastguard Worker int rtnl_netem_get_delay(struct rtnl_qdisc *qdisc)
785*4dc78e53SAndroid Build Coastguard Worker {
786*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem;
787*4dc78e53SAndroid Build Coastguard Worker 
788*4dc78e53SAndroid Build Coastguard Worker 	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
789*4dc78e53SAndroid Build Coastguard Worker 		BUG();
790*4dc78e53SAndroid Build Coastguard Worker 
791*4dc78e53SAndroid Build Coastguard Worker 	if (netem->qnm_mask & SCH_NETEM_ATTR_LATENCY)
792*4dc78e53SAndroid Build Coastguard Worker 		return nl_ticks2us(netem->qnm_latency);
793*4dc78e53SAndroid Build Coastguard Worker 	else
794*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOATTR;
795*4dc78e53SAndroid Build Coastguard Worker }
796*4dc78e53SAndroid Build Coastguard Worker 
797*4dc78e53SAndroid Build Coastguard Worker /**
798*4dc78e53SAndroid Build Coastguard Worker  * Set packet delay jitter of netem qdisc.
799*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		Netem qdisc to be modified.
800*4dc78e53SAndroid Build Coastguard Worker  * @arg jitter		New packet delay jitter in micro seconds.
801*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success or a negative error code.
802*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_netem_set_jitter(struct rtnl_qdisc * qdisc,int jitter)803*4dc78e53SAndroid Build Coastguard Worker void rtnl_netem_set_jitter(struct rtnl_qdisc *qdisc, int jitter)
804*4dc78e53SAndroid Build Coastguard Worker {
805*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem;
806*4dc78e53SAndroid Build Coastguard Worker 
807*4dc78e53SAndroid Build Coastguard Worker 	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
808*4dc78e53SAndroid Build Coastguard Worker 		BUG();
809*4dc78e53SAndroid Build Coastguard Worker 
810*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_jitter = nl_us2ticks(jitter);
811*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_mask |= SCH_NETEM_ATTR_JITTER;
812*4dc78e53SAndroid Build Coastguard Worker }
813*4dc78e53SAndroid Build Coastguard Worker 
814*4dc78e53SAndroid Build Coastguard Worker /**
815*4dc78e53SAndroid Build Coastguard Worker  * Get packet delay jitter of netem qdisc.
816*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		Netem qdisc.
817*4dc78e53SAndroid Build Coastguard Worker  * @return Packet delay jitter in micro seconds or a negative error code.
818*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_netem_get_jitter(struct rtnl_qdisc * qdisc)819*4dc78e53SAndroid Build Coastguard Worker int rtnl_netem_get_jitter(struct rtnl_qdisc *qdisc)
820*4dc78e53SAndroid Build Coastguard Worker {
821*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem;
822*4dc78e53SAndroid Build Coastguard Worker 
823*4dc78e53SAndroid Build Coastguard Worker 	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
824*4dc78e53SAndroid Build Coastguard Worker 		BUG();
825*4dc78e53SAndroid Build Coastguard Worker 
826*4dc78e53SAndroid Build Coastguard Worker 	if (netem->qnm_mask & SCH_NETEM_ATTR_JITTER)
827*4dc78e53SAndroid Build Coastguard Worker 		return nl_ticks2us(netem->qnm_jitter);
828*4dc78e53SAndroid Build Coastguard Worker 	else
829*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOATTR;
830*4dc78e53SAndroid Build Coastguard Worker }
831*4dc78e53SAndroid Build Coastguard Worker 
832*4dc78e53SAndroid Build Coastguard Worker /**
833*4dc78e53SAndroid Build Coastguard Worker  * Set packet delay correlation probability of netem qdisc.
834*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		Netem qdisc to be modified.
835*4dc78e53SAndroid Build Coastguard Worker  * @arg prob		New packet delay correlation probability.
836*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_netem_set_delay_correlation(struct rtnl_qdisc * qdisc,int prob)837*4dc78e53SAndroid Build Coastguard Worker void rtnl_netem_set_delay_correlation(struct rtnl_qdisc *qdisc, int prob)
838*4dc78e53SAndroid Build Coastguard Worker {
839*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem;
840*4dc78e53SAndroid Build Coastguard Worker 
841*4dc78e53SAndroid Build Coastguard Worker 	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
842*4dc78e53SAndroid Build Coastguard Worker 		BUG();
843*4dc78e53SAndroid Build Coastguard Worker 
844*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_corr.nmc_delay = prob;
845*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_mask |= SCH_NETEM_ATTR_DELAY_CORR;
846*4dc78e53SAndroid Build Coastguard Worker }
847*4dc78e53SAndroid Build Coastguard Worker 
848*4dc78e53SAndroid Build Coastguard Worker /**
849*4dc78e53SAndroid Build Coastguard Worker  * Get packet delay correlation probability of netem qdisc.
850*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		Netem qdisc.
851*4dc78e53SAndroid Build Coastguard Worker  * @return Packet delay correlation probability or a negative error code.
852*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_netem_get_delay_correlation(struct rtnl_qdisc * qdisc)853*4dc78e53SAndroid Build Coastguard Worker int rtnl_netem_get_delay_correlation(struct rtnl_qdisc *qdisc)
854*4dc78e53SAndroid Build Coastguard Worker {
855*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem;
856*4dc78e53SAndroid Build Coastguard Worker 
857*4dc78e53SAndroid Build Coastguard Worker 	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
858*4dc78e53SAndroid Build Coastguard Worker 		BUG();
859*4dc78e53SAndroid Build Coastguard Worker 
860*4dc78e53SAndroid Build Coastguard Worker 	if (netem->qnm_mask & SCH_NETEM_ATTR_DELAY_CORR)
861*4dc78e53SAndroid Build Coastguard Worker 		return netem->qnm_corr.nmc_delay;
862*4dc78e53SAndroid Build Coastguard Worker 	else
863*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOATTR;
864*4dc78e53SAndroid Build Coastguard Worker }
865*4dc78e53SAndroid Build Coastguard Worker 
866*4dc78e53SAndroid Build Coastguard Worker /**
867*4dc78e53SAndroid Build Coastguard Worker  * Get the size of the distribution table.
868*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		Netem qdisc.
869*4dc78e53SAndroid Build Coastguard Worker  * @return Distribution table size or a negative error code.
870*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_netem_get_delay_distribution_size(struct rtnl_qdisc * qdisc)871*4dc78e53SAndroid Build Coastguard Worker int rtnl_netem_get_delay_distribution_size(struct rtnl_qdisc *qdisc)
872*4dc78e53SAndroid Build Coastguard Worker {
873*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem;
874*4dc78e53SAndroid Build Coastguard Worker 
875*4dc78e53SAndroid Build Coastguard Worker 	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
876*4dc78e53SAndroid Build Coastguard Worker 		BUG();
877*4dc78e53SAndroid Build Coastguard Worker 
878*4dc78e53SAndroid Build Coastguard Worker 	if (netem->qnm_mask & SCH_NETEM_ATTR_DIST)
879*4dc78e53SAndroid Build Coastguard Worker 		return netem->qnm_dist.dist_size;
880*4dc78e53SAndroid Build Coastguard Worker 	else
881*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOATTR;
882*4dc78e53SAndroid Build Coastguard Worker }
883*4dc78e53SAndroid Build Coastguard Worker 
884*4dc78e53SAndroid Build Coastguard Worker /**
885*4dc78e53SAndroid Build Coastguard Worker  * Get a pointer to the distribution table.
886*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc		Netem qdisc.
887*4dc78e53SAndroid Build Coastguard Worker  * @arg dist_ptr	The pointer to set.
888*4dc78e53SAndroid Build Coastguard Worker  * @return Negative error code on failure or 0 on success.
889*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_netem_get_delay_distribution(struct rtnl_qdisc * qdisc,int16_t ** dist_ptr)890*4dc78e53SAndroid Build Coastguard Worker int rtnl_netem_get_delay_distribution(struct rtnl_qdisc *qdisc, int16_t **dist_ptr)
891*4dc78e53SAndroid Build Coastguard Worker {
892*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem;
893*4dc78e53SAndroid Build Coastguard Worker 
894*4dc78e53SAndroid Build Coastguard Worker 	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
895*4dc78e53SAndroid Build Coastguard Worker 		BUG();
896*4dc78e53SAndroid Build Coastguard Worker 
897*4dc78e53SAndroid Build Coastguard Worker 	if (netem->qnm_mask & SCH_NETEM_ATTR_DIST) {
898*4dc78e53SAndroid Build Coastguard Worker 		*dist_ptr = netem->qnm_dist.dist_data;
899*4dc78e53SAndroid Build Coastguard Worker 		return 0;
900*4dc78e53SAndroid Build Coastguard Worker 	} else
901*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOATTR;
902*4dc78e53SAndroid Build Coastguard Worker }
903*4dc78e53SAndroid Build Coastguard Worker 
904*4dc78e53SAndroid Build Coastguard Worker /**
905*4dc78e53SAndroid Build Coastguard Worker  * Set the delay distribution data. Latency/jitter must be set before applying.
906*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc Netem qdisc.
907*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success, error code on failure.
908*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_netem_set_delay_distribution_data(struct rtnl_qdisc * qdisc,const int16_t * data,size_t len)909*4dc78e53SAndroid Build Coastguard Worker int rtnl_netem_set_delay_distribution_data(struct rtnl_qdisc *qdisc, const int16_t *data, size_t len) {
910*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_netem *netem;
911*4dc78e53SAndroid Build Coastguard Worker 	int16_t *new_data;
912*4dc78e53SAndroid Build Coastguard Worker 
913*4dc78e53SAndroid Build Coastguard Worker 	if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
914*4dc78e53SAndroid Build Coastguard Worker 		BUG();
915*4dc78e53SAndroid Build Coastguard Worker 
916*4dc78e53SAndroid Build Coastguard Worker 	if (len > MAXDIST)
917*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_INVAL;
918*4dc78e53SAndroid Build Coastguard Worker 
919*4dc78e53SAndroid Build Coastguard Worker 	new_data = (int16_t *) calloc(len, sizeof(int16_t));
920*4dc78e53SAndroid Build Coastguard Worker 	if (!new_data)
921*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
922*4dc78e53SAndroid Build Coastguard Worker 
923*4dc78e53SAndroid Build Coastguard Worker 	free (netem->qnm_dist.dist_data);
924*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_dist.dist_data = new_data;
925*4dc78e53SAndroid Build Coastguard Worker 
926*4dc78e53SAndroid Build Coastguard Worker 	memcpy(netem->qnm_dist.dist_data, data, len * sizeof(int16_t));
927*4dc78e53SAndroid Build Coastguard Worker 
928*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_dist.dist_size = len;
929*4dc78e53SAndroid Build Coastguard Worker 	netem->qnm_mask |= SCH_NETEM_ATTR_DIST;
930*4dc78e53SAndroid Build Coastguard Worker 
931*4dc78e53SAndroid Build Coastguard Worker 	return 0;
932*4dc78e53SAndroid Build Coastguard Worker }
933*4dc78e53SAndroid Build Coastguard Worker 
934*4dc78e53SAndroid Build Coastguard Worker /**
935*4dc78e53SAndroid Build Coastguard Worker  * Load the delay distribution from a file. Latency/jitter must be set before applying.
936*4dc78e53SAndroid Build Coastguard Worker  * @arg qdisc Netem qdisc.
937*4dc78e53SAndroid Build Coastguard Worker  * @arg dist_type The name of the distribution (type, file, path/file).
938*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success, error code on failure.
939*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_netem_set_delay_distribution(struct rtnl_qdisc * qdisc,const char * dist_type)940*4dc78e53SAndroid Build Coastguard Worker int rtnl_netem_set_delay_distribution(struct rtnl_qdisc *qdisc, const char *dist_type) {
941*4dc78e53SAndroid Build Coastguard Worker 	FILE *f;
942*4dc78e53SAndroid Build Coastguard Worker 	int n = 0;
943*4dc78e53SAndroid Build Coastguard Worker 	size_t i;
944*4dc78e53SAndroid Build Coastguard Worker 	size_t len = 2048;
945*4dc78e53SAndroid Build Coastguard Worker 	_nl_auto_free char *line = NULL;
946*4dc78e53SAndroid Build Coastguard Worker 	char name[NAME_MAX];
947*4dc78e53SAndroid Build Coastguard Worker 	char dist_suffix[] = ".dist";
948*4dc78e53SAndroid Build Coastguard Worker 	_nl_auto_free int16_t *data = NULL;
949*4dc78e53SAndroid Build Coastguard Worker 	char *test_suffix;
950*4dc78e53SAndroid Build Coastguard Worker 
951*4dc78e53SAndroid Build Coastguard Worker 	/* Check several locations for the dist file */
952*4dc78e53SAndroid Build Coastguard Worker 	char *test_path[] = {
953*4dc78e53SAndroid Build Coastguard Worker 		"",
954*4dc78e53SAndroid Build Coastguard Worker 		"./",
955*4dc78e53SAndroid Build Coastguard Worker 		"/usr/lib/tc/",
956*4dc78e53SAndroid Build Coastguard Worker 		"/usr/lib64/tc/",
957*4dc78e53SAndroid Build Coastguard Worker 		"/usr/local/lib/tc/",
958*4dc78e53SAndroid Build Coastguard Worker 	};
959*4dc78e53SAndroid Build Coastguard Worker 
960*4dc78e53SAndroid Build Coastguard Worker 	/* If the given filename already ends in .dist, don't append it later */
961*4dc78e53SAndroid Build Coastguard Worker 	test_suffix = strstr(dist_type, dist_suffix);
962*4dc78e53SAndroid Build Coastguard Worker 	if (test_suffix != NULL && strlen(test_suffix) == 5)
963*4dc78e53SAndroid Build Coastguard Worker 		strcpy(dist_suffix, "");
964*4dc78e53SAndroid Build Coastguard Worker 
965*4dc78e53SAndroid Build Coastguard Worker 	for (i = 0; i < ARRAY_SIZE(test_path); i++) {
966*4dc78e53SAndroid Build Coastguard Worker 		snprintf(name, NAME_MAX, "%s%s%s", test_path[i], dist_type, dist_suffix);
967*4dc78e53SAndroid Build Coastguard Worker 		if ((f = fopen(name, "re")))
968*4dc78e53SAndroid Build Coastguard Worker 			break;
969*4dc78e53SAndroid Build Coastguard Worker 	}
970*4dc78e53SAndroid Build Coastguard Worker 
971*4dc78e53SAndroid Build Coastguard Worker 	if (f == NULL)
972*4dc78e53SAndroid Build Coastguard Worker 		return -nl_syserr2nlerr(errno);
973*4dc78e53SAndroid Build Coastguard Worker 
974*4dc78e53SAndroid Build Coastguard Worker 	data = (int16_t *) calloc(MAXDIST, sizeof(int16_t));
975*4dc78e53SAndroid Build Coastguard Worker 	line = (char *) calloc(len + 1, sizeof(char));
976*4dc78e53SAndroid Build Coastguard Worker 	if (!data || !line) {
977*4dc78e53SAndroid Build Coastguard Worker 	    fclose(f);
978*4dc78e53SAndroid Build Coastguard Worker 	    return -NLE_NOMEM;
979*4dc78e53SAndroid Build Coastguard Worker 	}
980*4dc78e53SAndroid Build Coastguard Worker 
981*4dc78e53SAndroid Build Coastguard Worker 	while (getline(&line, &len, f) != -1) {
982*4dc78e53SAndroid Build Coastguard Worker 		char *p, *endp;
983*4dc78e53SAndroid Build Coastguard Worker 
984*4dc78e53SAndroid Build Coastguard Worker 		if (*line == '\n' || *line == '#')
985*4dc78e53SAndroid Build Coastguard Worker 			continue;
986*4dc78e53SAndroid Build Coastguard Worker 
987*4dc78e53SAndroid Build Coastguard Worker 		for (p = line; ; p = endp) {
988*4dc78e53SAndroid Build Coastguard Worker 			long x = strtol(p, &endp, 0);
989*4dc78e53SAndroid Build Coastguard Worker 			if (endp == p) break;
990*4dc78e53SAndroid Build Coastguard Worker 
991*4dc78e53SAndroid Build Coastguard Worker 			if (n >= MAXDIST) {
992*4dc78e53SAndroid Build Coastguard Worker 				fclose(f);
993*4dc78e53SAndroid Build Coastguard Worker 				return -NLE_INVAL;
994*4dc78e53SAndroid Build Coastguard Worker 			}
995*4dc78e53SAndroid Build Coastguard Worker 			data[n++] = x;
996*4dc78e53SAndroid Build Coastguard Worker 		}
997*4dc78e53SAndroid Build Coastguard Worker 	}
998*4dc78e53SAndroid Build Coastguard Worker 
999*4dc78e53SAndroid Build Coastguard Worker 	fclose(f);
1000*4dc78e53SAndroid Build Coastguard Worker 	i = rtnl_netem_set_delay_distribution_data(qdisc, data, n);
1001*4dc78e53SAndroid Build Coastguard Worker 	return i;
1002*4dc78e53SAndroid Build Coastguard Worker }
1003*4dc78e53SAndroid Build Coastguard Worker 
1004*4dc78e53SAndroid Build Coastguard Worker /** @} */
1005*4dc78e53SAndroid Build Coastguard Worker 
1006*4dc78e53SAndroid Build Coastguard Worker static struct rtnl_tc_ops netem_ops = {
1007*4dc78e53SAndroid Build Coastguard Worker 	.to_kind		= "netem",
1008*4dc78e53SAndroid Build Coastguard Worker 	.to_type		= RTNL_TC_TYPE_QDISC,
1009*4dc78e53SAndroid Build Coastguard Worker 	.to_size		= sizeof(struct rtnl_netem),
1010*4dc78e53SAndroid Build Coastguard Worker 	.to_msg_parser		= netem_msg_parser,
1011*4dc78e53SAndroid Build Coastguard Worker 	.to_free_data		= netem_free_data,
1012*4dc78e53SAndroid Build Coastguard Worker 	.to_dump[NL_DUMP_LINE]	= netem_dump_line,
1013*4dc78e53SAndroid Build Coastguard Worker 	.to_dump[NL_DUMP_DETAILS] = netem_dump_details,
1014*4dc78e53SAndroid Build Coastguard Worker 	.to_msg_fill_raw	= netem_msg_fill_raw,
1015*4dc78e53SAndroid Build Coastguard Worker };
1016*4dc78e53SAndroid Build Coastguard Worker 
netem_init(void)1017*4dc78e53SAndroid Build Coastguard Worker static void _nl_init netem_init(void)
1018*4dc78e53SAndroid Build Coastguard Worker {
1019*4dc78e53SAndroid Build Coastguard Worker 	rtnl_tc_register(&netem_ops);
1020*4dc78e53SAndroid Build Coastguard Worker }
1021*4dc78e53SAndroid Build Coastguard Worker 
netem_exit(void)1022*4dc78e53SAndroid Build Coastguard Worker static void _nl_exit netem_exit(void)
1023*4dc78e53SAndroid Build Coastguard Worker {
1024*4dc78e53SAndroid Build Coastguard Worker 	rtnl_tc_unregister(&netem_ops);
1025*4dc78e53SAndroid Build Coastguard Worker }
1026*4dc78e53SAndroid Build Coastguard Worker 
1027*4dc78e53SAndroid Build Coastguard Worker /** @} */
1028