]>
Commit | Line | Data |
---|---|---|
c3524efc ED |
1 | /* |
2 | * Fair Queue Codel | |
3 | * | |
df1c7d91 | 4 | * Copyright (C) 2012,2015 Eric Dumazet <edumazet@google.com> |
c3524efc ED |
5 | * |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
9 | * 1. Redistributions of source code must retain the above copyright | |
10 | * notice, this list of conditions, and the following disclaimer, | |
11 | * without modification. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | |
15 | * 3. The names of the authors may not be used to endorse or promote products | |
16 | * derived from this software without specific prior written permission. | |
17 | * | |
18 | * Alternatively, provided that this notice is retained in full, this | |
19 | * software may be distributed under the terms of the GNU General | |
20 | * Public License ("GPL") version 2, in which case the provisions of the | |
21 | * GPL apply INSTEAD OF those given above. | |
22 | * | |
23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
24 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
25 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
26 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
27 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
28 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
29 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
30 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
31 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
32 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
33 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | |
34 | * DAMAGE. | |
35 | * | |
36 | */ | |
37 | ||
38 | #include <stdio.h> | |
39 | #include <stdlib.h> | |
40 | #include <unistd.h> | |
c3524efc ED |
41 | #include <fcntl.h> |
42 | #include <sys/socket.h> | |
43 | #include <netinet/in.h> | |
44 | #include <arpa/inet.h> | |
45 | #include <string.h> | |
46 | ||
47 | #include "utils.h" | |
48 | #include "tc_util.h" | |
49 | ||
50 | static void explain(void) | |
51 | { | |
8589eb4e MC |
52 | fprintf(stderr, |
53 | "Usage: ... fq_codel [ limit PACKETS ] [ flows NUMBER ]\n" | |
54 | "[ memory_limit BYTES ]\n" | |
55 | "[ target TIME ] [ interval TIME ]\n" | |
56 | "[ quantum BYTES ] [ [no]ecn ]\n" | |
57 | "[ ce_threshold TIME ]\n"); | |
c3524efc ED |
58 | } |
59 | ||
60 | static int fq_codel_parse_opt(struct qdisc_util *qu, int argc, char **argv, | |
927e3cfb | 61 | struct nlmsghdr *n, const char *dev) |
c3524efc | 62 | { |
32a121cb SH |
63 | unsigned int limit = 0; |
64 | unsigned int flows = 0; | |
65 | unsigned int target = 0; | |
66 | unsigned int interval = 0; | |
67 | unsigned int quantum = 0; | |
68 | unsigned int ce_threshold = ~0U; | |
4de4b5ca | 69 | unsigned int memory = ~0U; |
c3524efc ED |
70 | int ecn = -1; |
71 | struct rtattr *tail; | |
72 | ||
73 | while (argc > 0) { | |
74 | if (strcmp(*argv, "limit") == 0) { | |
75 | NEXT_ARG(); | |
76 | if (get_unsigned(&limit, *argv, 0)) { | |
77 | fprintf(stderr, "Illegal \"limit\"\n"); | |
78 | return -1; | |
79 | } | |
80 | } else if (strcmp(*argv, "flows") == 0) { | |
81 | NEXT_ARG(); | |
82 | if (get_unsigned(&flows, *argv, 0)) { | |
83 | fprintf(stderr, "Illegal \"flows\"\n"); | |
84 | return -1; | |
85 | } | |
86 | } else if (strcmp(*argv, "quantum") == 0) { | |
87 | NEXT_ARG(); | |
88 | if (get_unsigned(&quantum, *argv, 0)) { | |
89 | fprintf(stderr, "Illegal \"quantum\"\n"); | |
90 | return -1; | |
91 | } | |
92 | } else if (strcmp(*argv, "target") == 0) { | |
93 | NEXT_ARG(); | |
94 | if (get_time(&target, *argv)) { | |
95 | fprintf(stderr, "Illegal \"target\"\n"); | |
96 | return -1; | |
97 | } | |
df1c7d91 ED |
98 | } else if (strcmp(*argv, "ce_threshold") == 0) { |
99 | NEXT_ARG(); | |
100 | if (get_time(&ce_threshold, *argv)) { | |
101 | fprintf(stderr, "Illegal \"ce_threshold\"\n"); | |
102 | return -1; | |
103 | } | |
4de4b5ca ED |
104 | } else if (strcmp(*argv, "memory_limit") == 0) { |
105 | NEXT_ARG(); | |
106 | if (get_size(&memory, *argv)) { | |
107 | fprintf(stderr, "Illegal \"memory_limit\"\n"); | |
108 | return -1; | |
109 | } | |
c3524efc ED |
110 | } else if (strcmp(*argv, "interval") == 0) { |
111 | NEXT_ARG(); | |
112 | if (get_time(&interval, *argv)) { | |
113 | fprintf(stderr, "Illegal \"interval\"\n"); | |
114 | return -1; | |
115 | } | |
116 | } else if (strcmp(*argv, "ecn") == 0) { | |
117 | ecn = 1; | |
118 | } else if (strcmp(*argv, "noecn") == 0) { | |
119 | ecn = 0; | |
120 | } else if (strcmp(*argv, "help") == 0) { | |
121 | explain(); | |
122 | return -1; | |
123 | } else { | |
124 | fprintf(stderr, "What is \"%s\"?\n", *argv); | |
125 | explain(); | |
126 | return -1; | |
127 | } | |
128 | argc--; argv++; | |
129 | } | |
130 | ||
c14f9d92 | 131 | tail = addattr_nest(n, 1024, TCA_OPTIONS); |
c3524efc ED |
132 | if (limit) |
133 | addattr_l(n, 1024, TCA_FQ_CODEL_LIMIT, &limit, sizeof(limit)); | |
134 | if (flows) | |
135 | addattr_l(n, 1024, TCA_FQ_CODEL_FLOWS, &flows, sizeof(flows)); | |
136 | if (quantum) | |
137 | addattr_l(n, 1024, TCA_FQ_CODEL_QUANTUM, &quantum, sizeof(quantum)); | |
138 | if (interval) | |
139 | addattr_l(n, 1024, TCA_FQ_CODEL_INTERVAL, &interval, sizeof(interval)); | |
140 | if (target) | |
141 | addattr_l(n, 1024, TCA_FQ_CODEL_TARGET, &target, sizeof(target)); | |
142 | if (ecn != -1) | |
143 | addattr_l(n, 1024, TCA_FQ_CODEL_ECN, &ecn, sizeof(ecn)); | |
df1c7d91 ED |
144 | if (ce_threshold != ~0U) |
145 | addattr_l(n, 1024, TCA_FQ_CODEL_CE_THRESHOLD, | |
146 | &ce_threshold, sizeof(ce_threshold)); | |
4de4b5ca ED |
147 | if (memory != ~0U) |
148 | addattr_l(n, 1024, TCA_FQ_CODEL_MEMORY_LIMIT, | |
149 | &memory, sizeof(memory)); | |
150 | ||
c14f9d92 | 151 | addattr_nest_end(n, tail); |
c3524efc ED |
152 | return 0; |
153 | } | |
154 | ||
155 | static int fq_codel_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) | |
156 | { | |
157 | struct rtattr *tb[TCA_FQ_CODEL_MAX + 1]; | |
32a121cb SH |
158 | unsigned int limit; |
159 | unsigned int flows; | |
160 | unsigned int interval; | |
161 | unsigned int target; | |
162 | unsigned int ecn; | |
163 | unsigned int quantum; | |
164 | unsigned int ce_threshold; | |
4de4b5ca | 165 | unsigned int memory_limit; |
32a121cb | 166 | |
c3524efc ED |
167 | SPRINT_BUF(b1); |
168 | ||
169 | if (opt == NULL) | |
170 | return 0; | |
171 | ||
172 | parse_rtattr_nested(tb, TCA_FQ_CODEL_MAX, opt); | |
173 | ||
174 | if (tb[TCA_FQ_CODEL_LIMIT] && | |
175 | RTA_PAYLOAD(tb[TCA_FQ_CODEL_LIMIT]) >= sizeof(__u32)) { | |
176 | limit = rta_getattr_u32(tb[TCA_FQ_CODEL_LIMIT]); | |
378ac491 | 177 | print_uint(PRINT_ANY, "limit", "limit %up ", limit); |
c3524efc ED |
178 | } |
179 | if (tb[TCA_FQ_CODEL_FLOWS] && | |
180 | RTA_PAYLOAD(tb[TCA_FQ_CODEL_FLOWS]) >= sizeof(__u32)) { | |
181 | flows = rta_getattr_u32(tb[TCA_FQ_CODEL_FLOWS]); | |
378ac491 | 182 | print_uint(PRINT_ANY, "flows", "flows %u ", flows); |
c3524efc ED |
183 | } |
184 | if (tb[TCA_FQ_CODEL_QUANTUM] && | |
185 | RTA_PAYLOAD(tb[TCA_FQ_CODEL_QUANTUM]) >= sizeof(__u32)) { | |
186 | quantum = rta_getattr_u32(tb[TCA_FQ_CODEL_QUANTUM]); | |
378ac491 | 187 | print_uint(PRINT_ANY, "quantum", "quantum %u ", quantum); |
c3524efc ED |
188 | } |
189 | if (tb[TCA_FQ_CODEL_TARGET] && | |
190 | RTA_PAYLOAD(tb[TCA_FQ_CODEL_TARGET]) >= sizeof(__u32)) { | |
191 | target = rta_getattr_u32(tb[TCA_FQ_CODEL_TARGET]); | |
378ac491 JP |
192 | print_uint(PRINT_JSON, "target", NULL, target); |
193 | print_string(PRINT_FP, NULL, "target %s ", | |
194 | sprint_time(target, b1)); | |
c3524efc | 195 | } |
df1c7d91 ED |
196 | if (tb[TCA_FQ_CODEL_CE_THRESHOLD] && |
197 | RTA_PAYLOAD(tb[TCA_FQ_CODEL_CE_THRESHOLD]) >= sizeof(__u32)) { | |
198 | ce_threshold = rta_getattr_u32(tb[TCA_FQ_CODEL_CE_THRESHOLD]); | |
378ac491 JP |
199 | print_uint(PRINT_JSON, "ce_threshold", NULL, ce_threshold); |
200 | print_string(PRINT_FP, NULL, "ce_threshold %s ", | |
201 | sprint_time(ce_threshold, b1)); | |
df1c7d91 | 202 | } |
c3524efc ED |
203 | if (tb[TCA_FQ_CODEL_INTERVAL] && |
204 | RTA_PAYLOAD(tb[TCA_FQ_CODEL_INTERVAL]) >= sizeof(__u32)) { | |
205 | interval = rta_getattr_u32(tb[TCA_FQ_CODEL_INTERVAL]); | |
378ac491 JP |
206 | print_uint(PRINT_JSON, "interval", NULL, interval); |
207 | print_string(PRINT_FP, NULL, "interval %s ", | |
208 | sprint_time(interval, b1)); | |
c3524efc | 209 | } |
4de4b5ca ED |
210 | if (tb[TCA_FQ_CODEL_MEMORY_LIMIT] && |
211 | RTA_PAYLOAD(tb[TCA_FQ_CODEL_MEMORY_LIMIT]) >= sizeof(__u32)) { | |
212 | memory_limit = rta_getattr_u32(tb[TCA_FQ_CODEL_MEMORY_LIMIT]); | |
378ac491 JP |
213 | print_uint(PRINT_JSON, "memory_limit", NULL, memory_limit); |
214 | print_string(PRINT_FP, NULL, "memory_limit %s ", | |
215 | sprint_size(memory_limit, b1)); | |
4de4b5ca | 216 | } |
c3524efc ED |
217 | if (tb[TCA_FQ_CODEL_ECN] && |
218 | RTA_PAYLOAD(tb[TCA_FQ_CODEL_ECN]) >= sizeof(__u32)) { | |
219 | ecn = rta_getattr_u32(tb[TCA_FQ_CODEL_ECN]); | |
220 | if (ecn) | |
378ac491 | 221 | print_bool(PRINT_ANY, "ecn", "ecn ", true); |
c3524efc ED |
222 | } |
223 | ||
224 | return 0; | |
225 | } | |
226 | ||
227 | static int fq_codel_print_xstats(struct qdisc_util *qu, FILE *f, | |
228 | struct rtattr *xstats) | |
229 | { | |
d17b136f | 230 | struct tc_fq_codel_xstats _st = {}, *st; |
32a121cb | 231 | |
c3524efc ED |
232 | SPRINT_BUF(b1); |
233 | ||
234 | if (xstats == NULL) | |
235 | return 0; | |
236 | ||
c3524efc | 237 | st = RTA_DATA(xstats); |
df1c7d91 | 238 | if (RTA_PAYLOAD(xstats) < sizeof(*st)) { |
df1c7d91 ED |
239 | memcpy(&_st, st, RTA_PAYLOAD(xstats)); |
240 | st = &_st; | |
241 | } | |
c3524efc | 242 | if (st->type == TCA_FQ_CODEL_XSTATS_QDISC) { |
997f2dc1 THJ |
243 | print_uint(PRINT_ANY, "maxpacket", " maxpacket %u", |
244 | st->qdisc_stats.maxpacket); | |
245 | print_uint(PRINT_ANY, "drop_overlimit", " drop_overlimit %u", | |
246 | st->qdisc_stats.drop_overlimit); | |
247 | print_uint(PRINT_ANY, "new_flow_count", " new_flow_count %u", | |
248 | st->qdisc_stats.new_flow_count); | |
249 | print_uint(PRINT_ANY, "ecn_mark", " ecn_mark %u", | |
c3524efc | 250 | st->qdisc_stats.ecn_mark); |
df1c7d91 | 251 | if (st->qdisc_stats.ce_mark) |
997f2dc1 THJ |
252 | print_uint(PRINT_ANY, "ce_mark", " ce_mark %u", |
253 | st->qdisc_stats.ce_mark); | |
4de4b5ca | 254 | if (st->qdisc_stats.memory_usage) |
997f2dc1 THJ |
255 | print_uint(PRINT_ANY, "memory_used", " memory_used %u", |
256 | st->qdisc_stats.memory_usage); | |
4de4b5ca | 257 | if (st->qdisc_stats.drop_overmemory) |
997f2dc1 THJ |
258 | print_uint(PRINT_ANY, "drop_overmemory", " drop_overmemory %u", |
259 | st->qdisc_stats.drop_overmemory); | |
260 | print_uint(PRINT_ANY, "new_flows_len", "\n new_flows_len %u", | |
261 | st->qdisc_stats.new_flows_len); | |
262 | print_uint(PRINT_ANY, "old_flows_len", " old_flows_len %u", | |
c3524efc ED |
263 | st->qdisc_stats.old_flows_len); |
264 | } | |
265 | if (st->type == TCA_FQ_CODEL_XSTATS_CLASS) { | |
997f2dc1 THJ |
266 | print_uint(PRINT_ANY, "deficit", " deficit %u", |
267 | st->class_stats.deficit); | |
268 | print_uint(PRINT_ANY, "count", " count %u", | |
269 | st->class_stats.count); | |
270 | print_uint(PRINT_ANY, "lastcount", " lastcount %u", | |
271 | st->class_stats.lastcount); | |
272 | print_uint(PRINT_JSON, "ldelay", NULL, | |
273 | st->class_stats.ldelay); | |
274 | print_string(PRINT_FP, NULL, " ldelay %s", | |
c3524efc ED |
275 | sprint_time(st->class_stats.ldelay, b1)); |
276 | if (st->class_stats.dropping) { | |
997f2dc1 | 277 | print_bool(PRINT_ANY, "dropping", " dropping", true); |
c3524efc | 278 | if (st->class_stats.drop_next < 0) |
997f2dc1 | 279 | print_string(PRINT_FP, NULL, " drop_next -%s", |
c3524efc | 280 | sprint_time(-st->class_stats.drop_next, b1)); |
997f2dc1 THJ |
281 | else { |
282 | print_uint(PRINT_JSON, "drop_next", NULL, | |
283 | st->class_stats.drop_next); | |
284 | print_string(PRINT_FP, NULL, " drop_next %s", | |
c3524efc | 285 | sprint_time(st->class_stats.drop_next, b1)); |
997f2dc1 | 286 | } |
c3524efc ED |
287 | } |
288 | } | |
289 | return 0; | |
290 | ||
291 | } | |
292 | ||
293 | struct qdisc_util fq_codel_qdisc_util = { | |
294 | .id = "fq_codel", | |
295 | .parse_qopt = fq_codel_parse_opt, | |
296 | .print_qopt = fq_codel_print_opt, | |
297 | .print_xstats = fq_codel_print_xstats, | |
298 | }; |