1dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat/*
2dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat * q_red.c		RED.
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:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
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
23dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include "utils.h"
24dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include "tc_util.h"
25dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
26dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include "tc_red.h"
27dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
28dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstatic void explain(void)
29dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
30dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	fprintf(stderr, "Usage: ... red limit BYTES min BYTES max BYTES avpkt BYTES burst PACKETS\n");
31dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	fprintf(stderr, "               probability PROBABILITY bandwidth KBPS [ ecn ]\n");
32dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
33dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
34dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstatic int red_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nlmsghdr *n)
35dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
36dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct tc_red_qopt opt;
37dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	unsigned burst = 0;
38dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	unsigned avpkt = 0;
39dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	double probability = 0.02;
40dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	unsigned rate = 0;
41dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	int ecn_ok = 0;
42dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	int wlog;
43dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	__u8 sbuf[256];
44dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct rtattr *tail;
45dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
46dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	memset(&opt, 0, sizeof(opt));
47dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
48dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	while (argc > 0) {
49dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (strcmp(*argv, "limit") == 0) {
50dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
51dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (get_size(&opt.limit, *argv)) {
52dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				fprintf(stderr, "Illegal \"limit\"\n");
53dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
54dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
55dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (strcmp(*argv, "min") == 0) {
56dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
57dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (get_size(&opt.qth_min, *argv)) {
58dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				fprintf(stderr, "Illegal \"min\"\n");
59dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
60dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
61dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (strcmp(*argv, "max") == 0) {
62dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
63dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (get_size(&opt.qth_max, *argv)) {
64dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				fprintf(stderr, "Illegal \"max\"\n");
65dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
66dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
67dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (strcmp(*argv, "burst") == 0) {
68dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
69dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (get_unsigned(&burst, *argv, 0)) {
70dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				fprintf(stderr, "Illegal \"burst\"\n");
71dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
72dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
73dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (strcmp(*argv, "avpkt") == 0) {
74dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
75dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (get_size(&avpkt, *argv)) {
76dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				fprintf(stderr, "Illegal \"avpkt\"\n");
77dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
78dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
79dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (strcmp(*argv, "probability") == 0) {
80dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
81dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (sscanf(*argv, "%lg", &probability) != 1) {
82dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				fprintf(stderr, "Illegal \"probability\"\n");
83dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
84dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
85dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (strcmp(*argv, "bandwidth") == 0) {
86dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
87dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (get_rate(&rate, *argv)) {
88dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				fprintf(stderr, "Illegal \"bandwidth\"\n");
89dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
90dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
91dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (strcmp(*argv, "ecn") == 0) {
92dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			ecn_ok = 1;
93dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (strcmp(*argv, "help") == 0) {
94dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			explain();
95dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			return -1;
96dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else {
97dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			fprintf(stderr, "What is \"%s\"?\n", *argv);
98dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			explain();
99dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			return -1;
100dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
101dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		argc--; argv++;
102dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
103dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
104dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (rate == 0)
105dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		get_rate(&rate, "10Mbit");
106dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
107dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (!opt.qth_min || !opt.qth_max || !burst || !opt.limit || !avpkt) {
1081a441f49ec87ef74b978d7ae17da2a9b2ca6e811Dmitry Shmidt		fprintf(stderr, "Required parameter (min, max, burst, limit, avpkt) is missing\n");
109dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
110dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
111dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
112dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if ((wlog = tc_red_eval_ewma(opt.qth_min, burst, avpkt)) < 0) {
113dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(stderr, "RED: failed to calculate EWMA constant.\n");
114dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
115dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
116dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (wlog >= 10)
117dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(stderr, "RED: WARNING. Burst %d seems to be to large.\n", burst);
118dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	opt.Wlog = wlog;
119dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if ((wlog = tc_red_eval_P(opt.qth_min, opt.qth_max, probability)) < 0) {
120dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(stderr, "RED: failed to calculate probability.\n");
121dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
122dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
123dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	opt.Plog = wlog;
124dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if ((wlog = tc_red_eval_idle_damping(opt.Wlog, avpkt, rate, sbuf)) < 0) {
125dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(stderr, "RED: failed to calculate idle damping table.\n");
126dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
127dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
128dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	opt.Scell_log = wlog;
129dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (ecn_ok) {
130dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#ifdef TC_RED_ECN
131dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		opt.flags |= TC_RED_ECN;
132dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#else
133dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(stderr, "RED: ECN support is missing in this binary.\n");
134dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
135dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#endif
136dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
137dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
138dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	tail = NLMSG_TAIL(n);
139dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
140dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	addattr_l(n, 1024, TCA_RED_PARMS, &opt, sizeof(opt));
141dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	addattr_l(n, 1024, TCA_RED_STAB, sbuf, 256);
142dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
143dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return 0;
144dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
145dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
146dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstatic int red_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
147dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
148dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct rtattr *tb[TCA_RED_STAB+1];
149dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct tc_red_qopt *qopt;
150dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	SPRINT_BUF(b1);
151dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	SPRINT_BUF(b2);
152dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	SPRINT_BUF(b3);
153dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
154dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (opt == NULL)
155dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return 0;
156dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
157dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	parse_rtattr_nested(tb, TCA_RED_STAB, opt);
158dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
159dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (tb[TCA_RED_PARMS] == NULL)
160dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
161dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	qopt = RTA_DATA(tb[TCA_RED_PARMS]);
162dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (RTA_PAYLOAD(tb[TCA_RED_PARMS])  < sizeof(*qopt))
163dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
164dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	fprintf(f, "limit %s min %s max %s ",
165dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		sprint_size(qopt->limit, b1),
166dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		sprint_size(qopt->qth_min, b2),
167dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		sprint_size(qopt->qth_max, b3));
168dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#ifdef TC_RED_ECN
169dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (qopt->flags & TC_RED_ECN)
170dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(f, "ecn ");
171dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#endif
172dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (show_details) {
173dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(f, "ewma %u Plog %u Scell_log %u",
174dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			qopt->Wlog, qopt->Plog, qopt->Scell_log);
175dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
176dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return 0;
177dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
178dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
179dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstatic int red_print_xstats(struct qdisc_util *qu, FILE *f, struct rtattr *xstats)
180dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
181dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#ifdef TC_RED_ECN
182dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct tc_red_xstats *st;
183dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
184dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (xstats == NULL)
185dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return 0;
186dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
187dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (RTA_PAYLOAD(xstats) < sizeof(*st))
188dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
189dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
190dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	st = RTA_DATA(xstats);
191dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	fprintf(f, "  marked %u early %u pdrop %u other %u",
192dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		st->marked, st->early, st->pdrop, st->other);
193dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return 0;
194dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
195dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#endif
196dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return 0;
197dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
198dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
199dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
200dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstruct qdisc_util red_qdisc_util = {
201dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	.id		= "red",
202dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	.parse_qopt	= red_parse_opt,
203dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	.print_qopt	= red_print_opt,
204dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	.print_xstats	= red_print_xstats,
205dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat};
206