1bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet/*
2bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet * Fair Queue
3bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet *
48d5bd8c302952c24b803b30093c880393935bf87Eric Dumazet *  Copyright (C) 2013-2015 Eric Dumazet <edumazet@google.com>
5bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet *
6bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet * Redistribution and use in source and binary forms, with or without
7bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet * modification, are permitted provided that the following conditions
8bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet * are met:
9bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet * 1. Redistributions of source code must retain the above copyright
10bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet *    notice, this list of conditions, and the following disclaimer,
11bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet *    without modification.
12bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet * 2. Redistributions in binary form must reproduce the above copyright
13bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet *    notice, this list of conditions and the following disclaimer in the
14bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet *    documentation and/or other materials provided with the distribution.
15bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet * 3. The names of the authors may not be used to endorse or promote products
16bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet *    derived from this software without specific prior written permission.
17bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet *
18bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet * Alternatively, provided that this notice is retained in full, this
19bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet * software may be distributed under the terms of the GNU General
20bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet * Public License ("GPL") version 2, in which case the provisions of the
21bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet * GPL apply INSTEAD OF those given above.
22bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet *
23bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
34bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet * DAMAGE.
35bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet *
36bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet */
37bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet
38bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet#include <stdio.h>
39bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet#include <stdlib.h>
40bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet#include <unistd.h>
41bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet#include <syslog.h>
42bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet#include <fcntl.h>
43bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet#include <sys/socket.h>
44bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet#include <netinet/in.h>
45bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet#include <arpa/inet.h>
46bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet#include <string.h>
47aeb199d5ce86c6c72decaac333cad5a7d7b38b3aYang Yingliang#include <stdbool.h>
48bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet
49bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet#include "utils.h"
50bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet#include "tc_util.h"
51bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet
52bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazetstatic void explain(void)
53bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet{
54bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	fprintf(stderr, "Usage: ... fq [ limit PACKETS ] [ flow_limit PACKETS ]\n");
55bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	fprintf(stderr, "              [ quantum BYTES ] [ initial_quantum BYTES ]\n");
56bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	fprintf(stderr, "              [ maxrate RATE  ] [ buckets NUMBER ]\n");
57565af7b8168416bb8432f9f10935b7897232e853Phil Sutter	fprintf(stderr, "              [ [no]pacing ] [ refill_delay TIME ]\n");
588d5bd8c302952c24b803b30093c880393935bf87Eric Dumazet	fprintf(stderr, "              [ orphan_mask MASK]\n");
59bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet}
60bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet
61bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazetstatic unsigned int ilog2(unsigned int val)
62bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet{
63bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	unsigned int res = 0;
64bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet
65bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	val--;
66bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	while (val) {
67bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		res++;
68bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		val >>= 1;
69bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	}
70bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	return res;
71bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet}
72bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet
73bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazetstatic int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
74bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			struct nlmsghdr *n)
75bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet{
76aeb199d5ce86c6c72decaac333cad5a7d7b38b3aYang Yingliang	unsigned int plimit;
77aeb199d5ce86c6c72decaac333cad5a7d7b38b3aYang Yingliang	unsigned int flow_plimit;
78aeb199d5ce86c6c72decaac333cad5a7d7b38b3aYang Yingliang	unsigned int quantum;
79aeb199d5ce86c6c72decaac333cad5a7d7b38b3aYang Yingliang	unsigned int initial_quantum;
80bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	unsigned int buckets = 0;
81aeb199d5ce86c6c72decaac333cad5a7d7b38b3aYang Yingliang	unsigned int maxrate;
82aeb199d5ce86c6c72decaac333cad5a7d7b38b3aYang Yingliang	unsigned int defrate;
83565af7b8168416bb8432f9f10935b7897232e853Phil Sutter	unsigned int refill_delay;
848d5bd8c302952c24b803b30093c880393935bf87Eric Dumazet	unsigned int orphan_mask;
85aeb199d5ce86c6c72decaac333cad5a7d7b38b3aYang Yingliang	bool set_plimit = false;
86aeb199d5ce86c6c72decaac333cad5a7d7b38b3aYang Yingliang	bool set_flow_plimit = false;
87aeb199d5ce86c6c72decaac333cad5a7d7b38b3aYang Yingliang	bool set_quantum = false;
88aeb199d5ce86c6c72decaac333cad5a7d7b38b3aYang Yingliang	bool set_initial_quantum = false;
89aeb199d5ce86c6c72decaac333cad5a7d7b38b3aYang Yingliang	bool set_maxrate = false;
90aeb199d5ce86c6c72decaac333cad5a7d7b38b3aYang Yingliang	bool set_defrate = false;
91565af7b8168416bb8432f9f10935b7897232e853Phil Sutter	bool set_refill_delay = false;
928d5bd8c302952c24b803b30093c880393935bf87Eric Dumazet	bool set_orphan_mask = false;
93bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	int pacing = -1;
94bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	struct rtattr *tail;
95bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet
96bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	while (argc > 0) {
97bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		if (strcmp(*argv, "limit") == 0) {
98bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			NEXT_ARG();
99bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			if (get_unsigned(&plimit, *argv, 0)) {
100bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet				fprintf(stderr, "Illegal \"limit\"\n");
101bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet				return -1;
102bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			}
103aeb199d5ce86c6c72decaac333cad5a7d7b38b3aYang Yingliang			set_plimit = true;
104bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		} else if (strcmp(*argv, "flow_limit") == 0) {
105bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			NEXT_ARG();
106bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			if (get_unsigned(&flow_plimit, *argv, 0)) {
107bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet				fprintf(stderr, "Illegal \"flow_limit\"\n");
108bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet				return -1;
109bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			}
110aeb199d5ce86c6c72decaac333cad5a7d7b38b3aYang Yingliang			set_flow_plimit = true;
111bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		} else if (strcmp(*argv, "buckets") == 0) {
112bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			NEXT_ARG();
113bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			if (get_unsigned(&buckets, *argv, 0)) {
114bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet				fprintf(stderr, "Illegal \"buckets\"\n");
115bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet				return -1;
116bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			}
117bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		} else if (strcmp(*argv, "maxrate") == 0) {
118bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			NEXT_ARG();
119bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			if (get_rate(&maxrate, *argv)) {
120bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet				fprintf(stderr, "Illegal \"maxrate\"\n");
121bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet				return -1;
122bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			}
123aeb199d5ce86c6c72decaac333cad5a7d7b38b3aYang Yingliang			set_maxrate = true;
124bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		} else if (strcmp(*argv, "defrate") == 0) {
125bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			NEXT_ARG();
126bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			if (get_rate(&defrate, *argv)) {
127bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet				fprintf(stderr, "Illegal \"defrate\"\n");
128bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet				return -1;
129bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			}
130aeb199d5ce86c6c72decaac333cad5a7d7b38b3aYang Yingliang			set_defrate = true;
131bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		} else if (strcmp(*argv, "quantum") == 0) {
132bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			NEXT_ARG();
133bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			if (get_unsigned(&quantum, *argv, 0)) {
134bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet				fprintf(stderr, "Illegal \"quantum\"\n");
135bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet				return -1;
136bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			}
137aeb199d5ce86c6c72decaac333cad5a7d7b38b3aYang Yingliang			set_quantum = true;
138bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		} else if (strcmp(*argv, "initial_quantum") == 0) {
139bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			NEXT_ARG();
140bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			if (get_unsigned(&initial_quantum, *argv, 0)) {
141bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet				fprintf(stderr, "Illegal \"initial_quantum\"\n");
142bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet				return -1;
143bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			}
144aeb199d5ce86c6c72decaac333cad5a7d7b38b3aYang Yingliang			set_initial_quantum = true;
1458d5bd8c302952c24b803b30093c880393935bf87Eric Dumazet		} else if (strcmp(*argv, "orphan_mask") == 0) {
1468d5bd8c302952c24b803b30093c880393935bf87Eric Dumazet			NEXT_ARG();
1478d5bd8c302952c24b803b30093c880393935bf87Eric Dumazet			if (get_unsigned(&orphan_mask, *argv, 0)) {
1488d5bd8c302952c24b803b30093c880393935bf87Eric Dumazet				fprintf(stderr, "Illegal \"initial_quantum\"\n");
1498d5bd8c302952c24b803b30093c880393935bf87Eric Dumazet				return -1;
1508d5bd8c302952c24b803b30093c880393935bf87Eric Dumazet			}
1518d5bd8c302952c24b803b30093c880393935bf87Eric Dumazet			set_orphan_mask = true;
152565af7b8168416bb8432f9f10935b7897232e853Phil Sutter		} else if (strcmp(*argv, "refill_delay") == 0) {
153565af7b8168416bb8432f9f10935b7897232e853Phil Sutter			NEXT_ARG();
154565af7b8168416bb8432f9f10935b7897232e853Phil Sutter			if (get_time(&refill_delay, *argv)) {
155565af7b8168416bb8432f9f10935b7897232e853Phil Sutter				fprintf(stderr, "Illegal \"refill_delay\"\n");
156565af7b8168416bb8432f9f10935b7897232e853Phil Sutter				return -1;
157565af7b8168416bb8432f9f10935b7897232e853Phil Sutter			}
158565af7b8168416bb8432f9f10935b7897232e853Phil Sutter			set_refill_delay = true;
159bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		} else if (strcmp(*argv, "pacing") == 0) {
160bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			pacing = 1;
161bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		} else if (strcmp(*argv, "nopacing") == 0) {
162bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			pacing = 0;
163bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		} else if (strcmp(*argv, "help") == 0) {
164bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			explain();
165bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			return -1;
166bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		} else {
167bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			fprintf(stderr, "What is \"%s\"?\n", *argv);
168bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			explain();
169bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			return -1;
170bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		}
171bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		argc--; argv++;
172bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	}
173bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet
174bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	tail = NLMSG_TAIL(n);
175bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
176bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	if (buckets) {
177bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		unsigned int log = ilog2(buckets);
178bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet
179bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		addattr_l(n, 1024, TCA_FQ_BUCKETS_LOG,
180bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			  &log, sizeof(log));
181bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	}
182aeb199d5ce86c6c72decaac333cad5a7d7b38b3aYang Yingliang	if (set_plimit)
183bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		addattr_l(n, 1024, TCA_FQ_PLIMIT,
184bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			  &plimit, sizeof(plimit));
185aeb199d5ce86c6c72decaac333cad5a7d7b38b3aYang Yingliang	if (set_flow_plimit)
186bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		addattr_l(n, 1024, TCA_FQ_FLOW_PLIMIT,
187bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			  &flow_plimit, sizeof(flow_plimit));
188aeb199d5ce86c6c72decaac333cad5a7d7b38b3aYang Yingliang	if (set_quantum)
189bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		addattr_l(n, 1024, TCA_FQ_QUANTUM, &quantum, sizeof(quantum));
190aeb199d5ce86c6c72decaac333cad5a7d7b38b3aYang Yingliang	if (set_initial_quantum)
191bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		addattr_l(n, 1024, TCA_FQ_INITIAL_QUANTUM,
192bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			  &initial_quantum, sizeof(initial_quantum));
193bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	if (pacing != -1)
194bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		addattr_l(n, 1024, TCA_FQ_RATE_ENABLE,
195bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			  &pacing, sizeof(pacing));
196aeb199d5ce86c6c72decaac333cad5a7d7b38b3aYang Yingliang	if (set_maxrate)
197bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		addattr_l(n, 1024, TCA_FQ_FLOW_MAX_RATE,
198bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			  &maxrate, sizeof(maxrate));
199aeb199d5ce86c6c72decaac333cad5a7d7b38b3aYang Yingliang	if (set_defrate)
200bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		addattr_l(n, 1024, TCA_FQ_FLOW_DEFAULT_RATE,
201bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			  &defrate, sizeof(defrate));
202565af7b8168416bb8432f9f10935b7897232e853Phil Sutter	if (set_refill_delay)
203565af7b8168416bb8432f9f10935b7897232e853Phil Sutter		addattr_l(n, 1024, TCA_FQ_FLOW_REFILL_DELAY,
2048fe9839857d73b770b8aa4e2d9753c6a2c20ad6dStephen Hemminger			  &refill_delay, sizeof(refill_delay));
2058d5bd8c302952c24b803b30093c880393935bf87Eric Dumazet	if (set_orphan_mask)
2068d5bd8c302952c24b803b30093c880393935bf87Eric Dumazet		addattr_l(n, 1024, TCA_FQ_ORPHAN_MASK,
2078fe9839857d73b770b8aa4e2d9753c6a2c20ad6dStephen Hemminger			  &orphan_mask, sizeof(refill_delay));
208bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
209bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	return 0;
210bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet}
211bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet
212bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazetstatic int fq_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
213bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet{
214bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	struct rtattr *tb[TCA_FQ_MAX + 1];
215bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	unsigned int plimit, flow_plimit;
216bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	unsigned int buckets_log;
217bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	int pacing;
218bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	unsigned int rate, quantum;
219565af7b8168416bb8432f9f10935b7897232e853Phil Sutter	unsigned int refill_delay;
2208d5bd8c302952c24b803b30093c880393935bf87Eric Dumazet	unsigned int orphan_mask;
221bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	SPRINT_BUF(b1);
222bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet
223bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	if (opt == NULL)
224bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		return 0;
225bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet
226bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	parse_rtattr_nested(tb, TCA_FQ_MAX, opt);
227bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet
228bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	if (tb[TCA_FQ_PLIMIT] &&
229bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	    RTA_PAYLOAD(tb[TCA_FQ_PLIMIT]) >= sizeof(__u32)) {
230bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		plimit = rta_getattr_u32(tb[TCA_FQ_PLIMIT]);
231bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		fprintf(f, "limit %up ", plimit);
232bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	}
233bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	if (tb[TCA_FQ_FLOW_PLIMIT] &&
234bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	    RTA_PAYLOAD(tb[TCA_FQ_FLOW_PLIMIT]) >= sizeof(__u32)) {
235bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		flow_plimit = rta_getattr_u32(tb[TCA_FQ_FLOW_PLIMIT]);
236bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		fprintf(f, "flow_limit %up ", flow_plimit);
237bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	}
238bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	if (tb[TCA_FQ_BUCKETS_LOG] &&
239bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	    RTA_PAYLOAD(tb[TCA_FQ_BUCKETS_LOG]) >= sizeof(__u32)) {
240bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		buckets_log = rta_getattr_u32(tb[TCA_FQ_BUCKETS_LOG]);
241bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		fprintf(f, "buckets %u ", 1U << buckets_log);
242bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	}
2438d5bd8c302952c24b803b30093c880393935bf87Eric Dumazet	if (tb[TCA_FQ_ORPHAN_MASK] &&
2448d5bd8c302952c24b803b30093c880393935bf87Eric Dumazet	    RTA_PAYLOAD(tb[TCA_FQ_ORPHAN_MASK]) >= sizeof(__u32)) {
2458d5bd8c302952c24b803b30093c880393935bf87Eric Dumazet		orphan_mask = rta_getattr_u32(tb[TCA_FQ_ORPHAN_MASK]);
2468d5bd8c302952c24b803b30093c880393935bf87Eric Dumazet		fprintf(f, "orphan_mask %u ", orphan_mask);
2478d5bd8c302952c24b803b30093c880393935bf87Eric Dumazet	}
248bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	if (tb[TCA_FQ_RATE_ENABLE] &&
249bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	    RTA_PAYLOAD(tb[TCA_FQ_RATE_ENABLE]) >= sizeof(int)) {
250bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		pacing = rta_getattr_u32(tb[TCA_FQ_RATE_ENABLE]);
251bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		if (pacing == 0)
252bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			fprintf(f, "nopacing ");
253bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	}
254bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	if (tb[TCA_FQ_QUANTUM] &&
255bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	    RTA_PAYLOAD(tb[TCA_FQ_QUANTUM]) >= sizeof(__u32)) {
256bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		quantum = rta_getattr_u32(tb[TCA_FQ_QUANTUM]);
257bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		fprintf(f, "quantum %u ", quantum);
258bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	}
259bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	if (tb[TCA_FQ_INITIAL_QUANTUM] &&
260bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	    RTA_PAYLOAD(tb[TCA_FQ_INITIAL_QUANTUM]) >= sizeof(__u32)) {
261bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		quantum = rta_getattr_u32(tb[TCA_FQ_INITIAL_QUANTUM]);
262bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		fprintf(f, "initial_quantum %u ", quantum);
263bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	}
264bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	if (tb[TCA_FQ_FLOW_MAX_RATE] &&
265bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	    RTA_PAYLOAD(tb[TCA_FQ_FLOW_MAX_RATE]) >= sizeof(__u32)) {
266bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		rate = rta_getattr_u32(tb[TCA_FQ_FLOW_MAX_RATE]);
267bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet
268bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		if (rate != ~0U)
269bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			fprintf(f, "maxrate %s ", sprint_rate(rate, b1));
270bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	}
271bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	if (tb[TCA_FQ_FLOW_DEFAULT_RATE] &&
272bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	    RTA_PAYLOAD(tb[TCA_FQ_FLOW_DEFAULT_RATE]) >= sizeof(__u32)) {
273bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		rate = rta_getattr_u32(tb[TCA_FQ_FLOW_DEFAULT_RATE]);
274bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet
275bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		if (rate != 0)
276bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			fprintf(f, "defrate %s ", sprint_rate(rate, b1));
277bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	}
278565af7b8168416bb8432f9f10935b7897232e853Phil Sutter	if (tb[TCA_FQ_FLOW_REFILL_DELAY] &&
279565af7b8168416bb8432f9f10935b7897232e853Phil Sutter	    RTA_PAYLOAD(tb[TCA_FQ_FLOW_REFILL_DELAY]) >= sizeof(__u32)) {
280565af7b8168416bb8432f9f10935b7897232e853Phil Sutter		refill_delay = rta_getattr_u32(tb[TCA_FQ_FLOW_REFILL_DELAY]);
281565af7b8168416bb8432f9f10935b7897232e853Phil Sutter		fprintf(f, "refill_delay %s ", sprint_time(refill_delay, b1));
282565af7b8168416bb8432f9f10935b7897232e853Phil Sutter	}
283bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet
284bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	return 0;
285bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet}
286bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet
287bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazetstatic int fq_print_xstats(struct qdisc_util *qu, FILE *f,
288bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			   struct rtattr *xstats)
289bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet{
290bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	struct tc_fq_qd_stats *st;
291bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet
292bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	if (xstats == NULL)
293bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		return 0;
294bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet
295bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	if (RTA_PAYLOAD(xstats) < sizeof(*st))
296bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		return -1;
297bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet
298bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	st = RTA_DATA(xstats);
299bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet
300bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	fprintf(f, "  %u flows (%u inactive, %u throttled)",
301bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		st->flows, st->inactive_flows, st->throttled_flows);
302bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet
303bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	if (st->time_next_delayed_flow > 0)
304bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		fprintf(f, ", next packet delay %llu ns", st->time_next_delayed_flow);
305bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet
306bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	fprintf(f, "\n  %llu gc, %llu highprio",
307bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		st->gc_flows, st->highprio_packets);
308bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet
309bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	if (st->tcp_retrans)
310bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		fprintf(f, ", %llu retrans", st->tcp_retrans);
311bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet
312bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	fprintf(f, ", %llu throttled", st->throttled);
313bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet
314bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	if (st->flows_plimit)
315bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		fprintf(f, ", %llu flows_plimit", st->flows_plimit);
316bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet
317bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	if (st->pkts_too_long || st->allocation_errors)
318bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet		fprintf(f, "\n  %llu too long pkts, %llu alloc errors\n",
319bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet			st->pkts_too_long, st->allocation_errors);
320bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet
321bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	return 0;
322bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet}
323bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet
324bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazetstruct qdisc_util fq_qdisc_util = {
325bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	.id		= "fq",
326bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	.parse_qopt	= fq_parse_opt,
327bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	.print_qopt	= fq_print_opt,
328bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet	.print_xstats	= fq_print_xstats,
329bc113e46a3cd06973b37b13c06db3f5f459502f8Eric Dumazet};
330