1dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat/*
2dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat * q_netem.c		NETEM.
3dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *
4dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *		This program is free software; you can redistribute it and/or
5dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *		modify it under the terms of the GNU General Public License
6dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *		as published by the Free Software Foundation; either version
7dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *		2 of the License, or (at your option) any later version.
8dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *
9dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat * Authors:	Stephen Hemminger <shemminger@osdl.org>
10dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *
11dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat */
12dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
13dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <stdio.h>
14dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <stdlib.h>
15dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <unistd.h>
16dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <syslog.h>
17dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <fcntl.h>
18dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <sys/socket.h>
19dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <netinet/in.h>
20dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <arpa/inet.h>
21dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <string.h>
22dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <errno.h>
23dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
24dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include "utils.h"
25dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include "tc_util.h"
26dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include "tc_common.h"
27dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
28dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstatic void explain(void)
29dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
30dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	fprintf(stderr,
31dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat"Usage: ... netem [ limit PACKETS ] \n" \
32dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat"                 [ delay TIME [ JITTER [CORRELATION]]]\n" \
33dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat"                 [ distribution {uniform|normal|pareto|paretonormal} ]\n" \
34dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat"                 [ drop PERCENT [CORRELATION]] \n" \
35dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat"                 [ corrupt PERCENT [CORRELATION]] \n" \
36dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat"                 [ duplicate PERCENT [CORRELATION]]\n" \
37dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat"                 [ reorder PRECENT [CORRELATION] [ gap DISTANCE ]]\n");
38dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
39dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
40dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstatic void explain1(const char *arg)
41dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
42dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	fprintf(stderr, "Illegal \"%s\"\n", arg);
43dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
44dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
45dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat/* Upper bound on size of distribution
46dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *  really (TCA_BUF_MAX - other headers) / sizeof (__s16)
47dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat */
48dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#define MAX_DIST	(16*1024)
49dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
50dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat/*
51dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat * Simplistic file parser for distrbution data.
52dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat * Format is:
53dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *	# comment line(s)
54dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *	data0 data1 ...
55dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat */
56dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstatic int get_distribution(const char *type, __s16 *data, int maxdata)
57dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
58dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	FILE *f;
59dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	int n;
60dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	long x;
61dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	size_t len;
62dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	char *line = NULL;
63dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	char name[128];
64dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
65dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	snprintf(name, sizeof(name), "%s/%s.dist", get_tc_lib(), type);
66dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if ((f = fopen(name, "r")) == NULL) {
67dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(stderr, "No distribution data for %s (%s: %s)\n",
68dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			type, name, strerror(errno));
69dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
70dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
71dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
72dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	n = 0;
73dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	while (getline(&line, &len, f) != -1) {
74dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		char *p, *endp;
75dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (*line == '\n' || *line == '#')
76dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			continue;
77dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
78dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		for (p = line; ; p = endp) {
79dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			x = strtol(p, &endp, 0);
80dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (endp == p)
81dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				break;
82dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
83dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (n >= maxdata) {
84dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				fprintf(stderr, "%s: too much data\n",
85dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					name);
86dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				n = -1;
87dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				goto error;
88dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
89dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			data[n++] = x;
90dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
91dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
92dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat error:
93dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	free(line);
94dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	fclose(f);
95dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return n;
96dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
97dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
98dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstatic int isnumber(const char *arg)
99dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
100dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	char *p;
101dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
102dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return strtod(arg, &p) != 0 || p != arg;
103dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
104dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
105dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#define NEXT_IS_NUMBER() (NEXT_ARG_OK() && isnumber(argv[1]))
106dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
107dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat/* Adjust for the fact that psched_ticks aren't always usecs
108dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat   (based on kernel PSCHED_CLOCK configuration */
109dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstatic int get_ticks(__u32 *ticks, const char *str)
110dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
111dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	unsigned t;
112dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
113dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if(get_time(&t, str))
114dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
115dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
116dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (tc_core_time2big(t)) {
117dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(stderr, "Illegal %u time (too large)\n", t);
118dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
119dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
120dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
121dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	*ticks = tc_core_time2tick(t);
122dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return 0;
123dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
124dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
125dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstatic int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
126dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			   struct nlmsghdr *n)
127dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
128dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	size_t dist_size = 0;
129dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct rtattr *tail;
130dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct tc_netem_qopt opt;
131dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct tc_netem_corr cor;
132dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct tc_netem_reorder reorder;
133dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct tc_netem_corrupt corrupt;
134dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	__s16 *dist_data = NULL;
135dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	int present[__TCA_NETEM_MAX];
136dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
137dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	memset(&opt, 0, sizeof(opt));
138dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	opt.limit = 1000;
139dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	memset(&cor, 0, sizeof(cor));
140dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	memset(&reorder, 0, sizeof(reorder));
141dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	memset(&corrupt, 0, sizeof(corrupt));
142dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	memset(present, 0, sizeof(present));
143dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
144dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	while (argc > 0) {
145dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (matches(*argv, "limit") == 0) {
146dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
147dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (get_size(&opt.limit, *argv)) {
148dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				explain1("limit");
149dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
150dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
151dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (matches(*argv, "latency") == 0 ||
152dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			   matches(*argv, "delay") == 0) {
153dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
154dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (get_ticks(&opt.latency, *argv)) {
155dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				explain1("latency");
156dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
157dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
158dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
159dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (NEXT_IS_NUMBER()) {
160dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				NEXT_ARG();
161dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				if (get_ticks(&opt.jitter, *argv)) {
162dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					explain1("latency");
163dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					return -1;
164dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				}
165dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
166dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				if (NEXT_IS_NUMBER()) {
167dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					NEXT_ARG();
168dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					++present[TCA_NETEM_CORR];
169dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					if (get_percent(&cor.delay_corr,							*argv)) {
170dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat						explain1("latency");
171dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat						return -1;
172dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					}
173dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				}
174dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
175dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (matches(*argv, "loss") == 0 ||
176dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			   matches(*argv, "drop") == 0) {
177dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
178dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (get_percent(&opt.loss, *argv)) {
179dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				explain1("loss");
180dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
181dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
182dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (NEXT_IS_NUMBER()) {
183dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				NEXT_ARG();
184dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				++present[TCA_NETEM_CORR];
185dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				if (get_percent(&cor.loss_corr, *argv)) {
186dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					explain1("loss");
187dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					return -1;
188dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				}
189dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
190dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (matches(*argv, "reorder") == 0) {
191dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
192dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			present[TCA_NETEM_REORDER] = 1;
193dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (get_percent(&reorder.probability, *argv)) {
194dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				explain1("reorder");
195dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
196dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
197dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (NEXT_IS_NUMBER()) {
198dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				NEXT_ARG();
199dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				++present[TCA_NETEM_CORR];
200dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				if (get_percent(&reorder.correlation, *argv)) {
201dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					explain1("reorder");
202dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					return -1;
203dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				}
204dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
205dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (matches(*argv, "corrupt") == 0) {
206dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
207dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			present[TCA_NETEM_CORRUPT] = 1;
208dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (get_percent(&corrupt.probability, *argv)) {
209dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				explain1("corrupt");
210dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
211dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
212dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (NEXT_IS_NUMBER()) {
213dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				NEXT_ARG();
214dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				++present[TCA_NETEM_CORR];
215dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				if (get_percent(&corrupt.correlation, *argv)) {
216dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					explain1("corrupt");
217dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					return -1;
218dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				}
219dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
220dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (matches(*argv, "gap") == 0) {
221dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
222dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (get_u32(&opt.gap, *argv, 0)) {
223dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				explain1("gap");
224dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
225dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
226dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (matches(*argv, "duplicate") == 0) {
227dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
228dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (get_percent(&opt.duplicate, *argv)) {
229dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				explain1("duplicate");
230dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
231dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
232dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (NEXT_IS_NUMBER()) {
233dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				NEXT_ARG();
234dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				if (get_percent(&cor.dup_corr, *argv)) {
235dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					explain1("duplicate");
236dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					return -1;
237dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				}
238dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
239dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (matches(*argv, "distribution") == 0) {
240dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
241dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			dist_data = calloc(sizeof(dist_data[0]), MAX_DIST);
242dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			dist_size = get_distribution(*argv, dist_data, MAX_DIST);
243dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (dist_size <= 0) {
244dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				free(dist_data);
245dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
246dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
247dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (strcmp(*argv, "help") == 0) {
248dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			explain();
249dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			return -1;
250dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else {
251dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(stderr, "What is \"%s\"?\n", *argv);
252dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			explain();
253dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			return -1;
254dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
255dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		argc--; argv++;
256dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
257dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
258dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	tail = NLMSG_TAIL(n);
259dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
260dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (reorder.probability) {
261dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (opt.latency == 0) {
262dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(stderr, "reordering not possible without specifying some delay\n");
263dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
264dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (opt.gap == 0)
265dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			opt.gap = 1;
266dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	} else if (opt.gap > 0) {
267dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(stderr, "gap specified without reorder probability\n");
268dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		explain();
269dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
270dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
271dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
272dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (dist_data && (opt.latency == 0 || opt.jitter == 0)) {
273dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(stderr, "distribution specified but no latency and jitter values\n");
274dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		explain();
275dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
276dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
277dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
278dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt)) < 0)
279dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
280dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
281dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (present[TCA_NETEM_CORR] &&
282dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	    addattr_l(n, 1024, TCA_NETEM_CORR, &cor, sizeof(cor)) < 0)
283dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			return -1;
284dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
285dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (present[TCA_NETEM_REORDER] &&
286dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	    addattr_l(n, 1024, TCA_NETEM_REORDER, &reorder, sizeof(reorder)) < 0)
287dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
288dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
289dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (present[TCA_NETEM_CORRUPT] &&
290dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	    addattr_l(n, 1024, TCA_NETEM_CORRUPT, &corrupt, sizeof(corrupt)) < 0)
291dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
292dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
293dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (dist_data) {
294dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (addattr_l(n, MAX_DIST * sizeof(dist_data[0]),
295dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			      TCA_NETEM_DELAY_DIST,
296dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			      dist_data, dist_size * sizeof(dist_data[0])) < 0)
297dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			return -1;
298dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		free(dist_data);
299dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
300dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
301dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return 0;
302dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
303dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
304dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstatic int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
305dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
306dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	const struct tc_netem_corr *cor = NULL;
307dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	const struct tc_netem_reorder *reorder = NULL;
308dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	const struct tc_netem_corrupt *corrupt = NULL;
309dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct tc_netem_qopt qopt;
310dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	int len = RTA_PAYLOAD(opt) - sizeof(qopt);
311dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	SPRINT_BUF(b1);
312dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
313dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (opt == NULL)
314dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return 0;
315dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
316dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (len < 0) {
317dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(stderr, "options size error\n");
318dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
319dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
320dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	memcpy(&qopt, RTA_DATA(opt), sizeof(qopt));
321dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
322dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (len > 0) {
323dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		struct rtattr *tb[TCA_NETEM_MAX+1];
324dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		parse_rtattr(tb, TCA_NETEM_MAX, RTA_DATA(opt) + sizeof(qopt),
325dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			     len);
326dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
327dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (tb[TCA_NETEM_CORR]) {
328dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (RTA_PAYLOAD(tb[TCA_NETEM_CORR]) < sizeof(*cor))
329dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
330dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			cor = RTA_DATA(tb[TCA_NETEM_CORR]);
331dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
332dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (tb[TCA_NETEM_REORDER]) {
333dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (RTA_PAYLOAD(tb[TCA_NETEM_REORDER]) < sizeof(*reorder))
334dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
335dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			reorder = RTA_DATA(tb[TCA_NETEM_REORDER]);
336dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
337dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (tb[TCA_NETEM_CORRUPT]) {
338dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (RTA_PAYLOAD(tb[TCA_NETEM_CORRUPT]) < sizeof(*corrupt))
339dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
340dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			corrupt = RTA_DATA(tb[TCA_NETEM_CORRUPT]);
341dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
342dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
343dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
344dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	fprintf(f, "limit %d", qopt.limit);
345dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
346dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (qopt.latency) {
347dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(f, " delay %s", sprint_ticks(qopt.latency, b1));
348dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
349dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (qopt.jitter) {
350dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(f, "  %s", sprint_ticks(qopt.jitter, b1));
351dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (cor && cor->delay_corr)
352dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				fprintf(f, " %s", sprint_percent(cor->delay_corr, b1));
353dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
354dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
355dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
356dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (qopt.loss) {
357dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(f, " loss %s", sprint_percent(qopt.loss, b1));
358dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (cor && cor->loss_corr)
359dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(f, " %s", sprint_percent(cor->loss_corr, b1));
360dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
361dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
362dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (qopt.duplicate) {
363dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(f, " duplicate %s",
364dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			sprint_percent(qopt.duplicate, b1));
365dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (cor && cor->dup_corr)
366dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(f, " %s", sprint_percent(cor->dup_corr, b1));
367dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
368dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
369dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (reorder && reorder->probability) {
370dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(f, " reorder %s",
371dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			sprint_percent(reorder->probability, b1));
372dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (reorder->correlation)
373dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(f, " %s",
374dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				sprint_percent(reorder->correlation, b1));
375dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
376dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
377dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (corrupt && corrupt->probability) {
378dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(f, " corrupt %s",
379dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			sprint_percent(corrupt->probability, b1));
380dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (corrupt->correlation)
381dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(f, " %s",
382dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				sprint_percent(corrupt->correlation, b1));
383dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
384dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
385dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (qopt.gap)
386dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(f, " gap %lu", (unsigned long)qopt.gap);
387dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
388dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return 0;
389dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
390dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
391dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstruct qdisc_util netem_qdisc_util = {
392dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	.id	   	= "netem",
393dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	.parse_qopt	= netem_parse_opt,
394dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	.print_qopt	= netem_print_opt,
395dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat};
396dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
397