q_netem.c revision 1a1d22a72284acf43f7aff5210db018076e66194
1309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger/*
2309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger * q_netem.c		NETEM.
3309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger *
4309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger *		This program is free software; you can redistribute it and/or
5309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger *		modify it under the terms of the GNU General Public License
6309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger *		as published by the Free Software Foundation; either version
7309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger *		2 of the License, or (at your option) any later version.
8309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger *
9309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger * Authors:	Stephen Hemminger <shemminger@osdl.org>
10309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger *
11309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger */
12309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger
13309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger#include <stdio.h>
14309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger#include <stdlib.h>
15309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger#include <unistd.h>
16309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger#include <syslog.h>
17309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger#include <fcntl.h>
18309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger#include <sys/socket.h>
19309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger#include <netinet/in.h>
20309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger#include <arpa/inet.h>
21309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger#include <string.h>
22b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger#include <errno.h>
23309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger
24309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger#include "utils.h"
25309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger#include "tc_util.h"
26b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger#include "tc_common.h"
27309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger
28309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemmingerstatic void explain(void)
29309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger{
30ffb79d06915fe3b1ee5d2e4e37c1db67c3c06cdfosdl.net!shemminger	fprintf(stderr,
31b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger"Usage: ... netem [ limit PACKETS ] \n" \
32b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger"		  [ delay TIME [ JITTER [CORRELATION]]]\n" \
33b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger"                 [ drop PERCENT [CORRELATION]] \n" \
34b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger"                 [ duplicate PERCENT [CORRELATION]]\n" \
35b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger"		  [ distribution {uniform|normal|pareto|paretonormal} ]\n" \
36b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger"                 [ gap PACKETS ]\n");
37309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger}
38309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger
39309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemmingerstatic void explain1(const char *arg)
40309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger{
41309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger	fprintf(stderr, "Illegal \"%s\"\n", arg);
42309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger}
43309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger
44309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger#define usage() return(-1)
45309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger
462e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger/*
472e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger * Simplistic file parser for distrbution data.
482e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger * Format is:
492e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger *	# comment line(s)
502e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger *	data0 data1
512e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger */
522e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger#define MAXDIST	65536
532e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemmingerstatic int get_distribution(const char *type, __s16 *data)
54b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger{
55b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger	FILE *f;
56b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger	int n;
572e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger	long x;
582e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger	size_t len;
592e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger	char *line;
602e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger	char name[128];
61b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger
622e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger	snprintf(name, sizeof(name), "/usr/lib/tc/%s.dist", type);
632e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger	if ((f = fopen(name, "r")) == NULL) {
64b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger		fprintf(stderr, "No distribution data for %s (%s: %s)\n",
652e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger			type, name, strerror(errno));
66b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger		return -1;
67b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger	}
68b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger
69b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger	n = 0;
702e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger	while (getline(&line, &len, f) != -1) {
712e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger		char *p, *endp;
722e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger		if (*line == '\n' || *line == '#')
73b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger			continue;
74b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger
752e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger		for (p = line; ; p = endp) {
762e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger			x = strtol(p, &endp, 0);
772e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger			if (endp == p)
782e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger				break;
792e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger
802e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger			if (n >= MAXDIST) {
812e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger				fprintf(stderr, "%s: too much data\n",
822e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger					name);
832e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger				n = -1;
842e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger				goto error;
852e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger			}
86b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger			data[n++] = x;
87b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger		}
88b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger	}
892e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger error:
902e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger	free(line);
91b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger	fclose(f);
92b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger	return n;
93b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger}
94b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger
95b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemmingerstatic int isnumber(const char *arg)
96b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger{
97b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger	char *p;
98b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger	(void) strtod(arg, &p);
99b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger	return (p != arg);
100b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger}
101b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger
102b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger#define NEXT_IS_NUMBER() (NEXT_ARG_OK() && isnumber(argv[1]))
103b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger
104b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger/* Adjust for the fact that psched_ticks aren't always usecs
105b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger   (based on kernel PSCHED_CLOCK configuration */
106b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemmingerstatic int get_ticks(__u32 *ticks, const char *str)
107b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger{
108b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger	unsigned t;
109b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger
110b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger	if(get_usecs(&t, str))
111b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger		return -1;
112b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger
113b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger	*ticks = tc_core_usec2tick(t);
114b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger	return 0;
115b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger}
116b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger
117b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemmingerstatic char *sprint_ticks(__u32 ticks, char *buf)
118b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger{
119b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger	return sprint_usecs(tc_core_tick2usec(ticks), buf);
120b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger}
121b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger
122b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger
123309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemmingerstatic int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
124309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger			   struct nlmsghdr *n)
125309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger{
1262e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger	size_t dist_size = 0;
1272e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger	struct rtattr *tail;
1282e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger	struct tc_netem_qopt opt;
1292e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger	struct tc_netem_corr cor;
1302e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger	__s16 dist_data[MAXDIST];
131309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger
1322e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger	memset(&opt, 0, sizeof(opt));
1332e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger	opt.limit = 1000;
1342e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger	memset(&cor, 0, sizeof(cor));
135309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger
136309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger	while (argc > 0) {
137309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger		if (matches(*argv, "limit") == 0) {
138309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger			NEXT_ARG();
1392e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger			if (get_size(&opt.limit, *argv)) {
140309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger				explain1("limit");
141309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger				return -1;
142309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger			}
143b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger		} else if (matches(*argv, "latency") == 0 ||
144b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger			   matches(*argv, "delay") == 0) {
145309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger			NEXT_ARG();
1462e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger			if (get_ticks(&opt.latency, *argv)) {
147309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger				explain1("latency");
148309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger				return -1;
149309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger			}
150b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger
151b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger			if (NEXT_IS_NUMBER()) {
152b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger				NEXT_ARG();
1532e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger				if (get_ticks(&opt.jitter, *argv)) {
154b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger					explain1("latency");
155b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger					return -1;
156b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger				}
157b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger
158b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger				if (NEXT_IS_NUMBER()) {
159b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger					NEXT_ARG();
1602e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger					if (get_percent(&cor.delay_corr,
161b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger							*argv)) {
162b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger						explain1("latency");
163b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger						return -1;
164b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger					}
165b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger				}
166b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger			}
167b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger		} else if (matches(*argv, "loss") == 0 ||
168b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger			   matches(*argv, "drop") == 0) {
169309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger			NEXT_ARG();
1702e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger			if (get_percent(&opt.loss, *argv)) {
171309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger				explain1("loss");
172309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger				return -1;
173309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger			}
174b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger			if (NEXT_IS_NUMBER()) {
175b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger				NEXT_ARG();
1762e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger				if (get_percent(&cor.loss_corr, *argv)) {
177b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger					explain1("loss");
178b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger					return -1;
179b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger				}
180b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger			}
181309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger		} else if (matches(*argv, "gap") == 0) {
182309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger			NEXT_ARG();
1832e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger			if (get_u32(&opt.gap, *argv, 0)) {
184309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger				explain1("gap");
185309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger				return -1;
186309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger			}
187ffb79d06915fe3b1ee5d2e4e37c1db67c3c06cdfosdl.net!shemminger		} else if (matches(*argv, "duplicate") == 0) {
188309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger			NEXT_ARG();
1892e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger			if (get_percent(&opt.duplicate, *argv)) {
190ffb79d06915fe3b1ee5d2e4e37c1db67c3c06cdfosdl.net!shemminger				explain1("duplicate");
191309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger				return -1;
192309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger			}
193b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger			if (NEXT_IS_NUMBER()) {
194b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger				NEXT_ARG();
1952e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger				if (get_percent(&cor.dup_corr, *argv)) {
196b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger					explain1("duplicate");
197b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger					return -1;
198b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger				}
199b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger			}
200b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger		} else if (matches(*argv, "distribution") == 0) {
201309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger			NEXT_ARG();
2022e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger			dist_size = get_distribution(*argv, dist_data);
2032e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger			if (dist_size < 0)
204309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger				return -1;
205309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger		} else if (strcmp(*argv, "help") == 0) {
206309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger			explain();
207309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger			return -1;
208309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger		} else {
209309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger			fprintf(stderr, "What is \"%s\"?\n", *argv);
210309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger			explain();
211309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger			return -1;
212309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger		}
213309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger		argc--; argv++;
214309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger	}
215309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger
2161a1d22a72284acf43f7aff5210db018076e66194n);	tail = NLMSG_TAIL(n);
217025dc69a25f016c3035212517bae481dafbb2651osdl.net!shemminger
2182e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger	addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt));
2192e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger	addattr_l(n, 1024, TCA_NETEM_CORR, &cor, sizeof(cor));
2202e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger
2212e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger	if (dist_size > 0) {
2222e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger		addattr_l(n, 32768, TCA_NETEM_DELAY_DIST,
2232e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger			  dist_data, dist_size*sizeof(dist_data[0]));
2242e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger	}
2251a1d22a72284acf43f7aff5210db018076e66194void *) NLMSG_TAIL(n) - (void *) tail;	tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
226b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger	return 0;
227309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger}
228309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger
229309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemmingerstatic int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
230309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger{
2312e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger	const struct tc_netem_corr *cor = NULL;
2322e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger	struct tc_netem_qopt qopt;
2332e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger	int len = RTA_PAYLOAD(opt) - sizeof(qopt);
234309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger	SPRINT_BUF(b1);
235309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger
236309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger	if (opt == NULL)
237309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger		return 0;
238309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger
2392e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger	if (len < 0) {
2402e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger		fprintf(stderr, "options size error\n");
241309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger		return -1;
242b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger	}
2432e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger	memcpy(&qopt, RTA_DATA(opt), sizeof(qopt));
2442e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger
2452e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger	if (len > 0) {
2462e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger		struct rtattr *tb[TCA_NETEM_MAX];
2472e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger		parse_rtattr(tb, TCA_NETEM_MAX, RTA_DATA(opt) + sizeof(qopt),
2482e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger			     len);
2492e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger
2502e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger		if (tb[TCA_NETEM_CORR]) {
2512e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger			if (RTA_PAYLOAD(tb[TCA_NETEM_CORR]) < sizeof(*cor))
2522e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger				return -1;
2532e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger			cor = RTA_DATA(tb[TCA_NETEM_CORR]);
2542e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger		}
2552e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger	}
256309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger
2572e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger	fprintf(f, "limit %d", qopt.limit);
25831fa60e00f6299328c4ae13a543c2e764b9379b7osdl.net!shemminger
2592e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger	if (qopt.latency) {
2602e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger		fprintf(f, " delay %s", sprint_ticks(qopt.latency, b1));
261b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger
2622e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger		if (qopt.jitter) {
2632e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger			fprintf(f, "  %s", sprint_ticks(qopt.jitter, b1));
2642e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger			if (cor && cor->delay_corr)
2652e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger				fprintf(f, " %s", sprint_percent(cor->delay_corr, b1));
266b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger		}
267b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger	}
268b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger
2692e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger	if (qopt.loss) {
2702e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger		fprintf(f, " loss %s", sprint_percent(qopt.loss, b1));
2712e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger		if (cor && cor->loss_corr)
2722e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger			fprintf(f, " %s", sprint_percent(cor->loss_corr, b1));
273b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger	}
274b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger
2752e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger	if (qopt.duplicate) {
276b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger		fprintf(f, " duplicate %s",
2772e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger			sprint_percent(qopt.duplicate, b1));
2782e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger		if (cor && cor->dup_corr)
2792e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger			fprintf(f, " %s", sprint_percent(cor->dup_corr, b1));
280b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger	}
281b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger
2822e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger	if (qopt.gap)
2832e21655e39099e6a9645483bdeeebbd9e24e2345osdl.net!shemminger		fprintf(f, " gap %lu", (unsigned long)qopt.gap);
284309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger
285309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger	return 0;
286309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger}
287309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger
28895812b56a5a66e7e9a21744cfe8bc0bb9791ea98net[shemminger]!kaberstruct qdisc_util netem_qdisc_util = {
28931fa60e00f6299328c4ae13a543c2e764b9379b7osdl.net!shemminger	.id	   	= "netem",
29031fa60e00f6299328c4ae13a543c2e764b9379b7osdl.net!shemminger	.parse_qopt	= netem_parse_opt,
29131fa60e00f6299328c4ae13a543c2e764b9379b7osdl.net!shemminger	.print_qopt	= netem_print_opt,
292309a4c90a5d4f648653de32807cd4146763913e9osdl.net!shemminger};
293b7be3d0cd2bd699c1bdaef960e7c7bf3ad5036d3osdl.net!shemminger
294