]>
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 | { | |
52 | fprintf(stderr, "Usage: ... fq_codel [ limit PACKETS ] [ flows NUMBER ]\n"); | |
d7d044ff | 53 | fprintf(stderr, " [ memory_limit BYTES ]\n"); |
4733b18a | 54 | fprintf(stderr, " [ target TIME ] [ interval TIME ]\n"); |
c3524efc | 55 | fprintf(stderr, " [ quantum BYTES ] [ [no]ecn ]\n"); |
df1c7d91 | 56 | fprintf(stderr, " [ ce_threshold TIME ]\n"); |
c3524efc ED |
57 | } |
58 | ||
59 | static int fq_codel_parse_opt(struct qdisc_util *qu, int argc, char **argv, | |
927e3cfb | 60 | struct nlmsghdr *n, const char *dev) |
c3524efc | 61 | { |
32a121cb SH |
62 | unsigned int limit = 0; |
63 | unsigned int flows = 0; | |
64 | unsigned int target = 0; | |
65 | unsigned int interval = 0; | |
66 | unsigned int quantum = 0; | |
67 | unsigned int ce_threshold = ~0U; | |
4de4b5ca | 68 | unsigned int memory = ~0U; |
c3524efc ED |
69 | int ecn = -1; |
70 | struct rtattr *tail; | |
71 | ||
72 | while (argc > 0) { | |
73 | if (strcmp(*argv, "limit") == 0) { | |
74 | NEXT_ARG(); | |
75 | if (get_unsigned(&limit, *argv, 0)) { | |
76 | fprintf(stderr, "Illegal \"limit\"\n"); | |
77 | return -1; | |
78 | } | |
79 | } else if (strcmp(*argv, "flows") == 0) { | |
80 | NEXT_ARG(); | |
81 | if (get_unsigned(&flows, *argv, 0)) { | |
82 | fprintf(stderr, "Illegal \"flows\"\n"); | |
83 | return -1; | |
84 | } | |
85 | } else if (strcmp(*argv, "quantum") == 0) { | |
86 | NEXT_ARG(); | |
87 | if (get_unsigned(&quantum, *argv, 0)) { | |
88 | fprintf(stderr, "Illegal \"quantum\"\n"); | |
89 | return -1; | |
90 | } | |
91 | } else if (strcmp(*argv, "target") == 0) { | |
92 | NEXT_ARG(); | |
93 | if (get_time(&target, *argv)) { | |
94 | fprintf(stderr, "Illegal \"target\"\n"); | |
95 | return -1; | |
96 | } | |
df1c7d91 ED |
97 | } else if (strcmp(*argv, "ce_threshold") == 0) { |
98 | NEXT_ARG(); | |
99 | if (get_time(&ce_threshold, *argv)) { | |
100 | fprintf(stderr, "Illegal \"ce_threshold\"\n"); | |
101 | return -1; | |
102 | } | |
4de4b5ca ED |
103 | } else if (strcmp(*argv, "memory_limit") == 0) { |
104 | NEXT_ARG(); | |
105 | if (get_size(&memory, *argv)) { | |
106 | fprintf(stderr, "Illegal \"memory_limit\"\n"); | |
107 | return -1; | |
108 | } | |
c3524efc ED |
109 | } else if (strcmp(*argv, "interval") == 0) { |
110 | NEXT_ARG(); | |
111 | if (get_time(&interval, *argv)) { | |
112 | fprintf(stderr, "Illegal \"interval\"\n"); | |
113 | return -1; | |
114 | } | |
115 | } else if (strcmp(*argv, "ecn") == 0) { | |
116 | ecn = 1; | |
117 | } else if (strcmp(*argv, "noecn") == 0) { | |
118 | ecn = 0; | |
119 | } else if (strcmp(*argv, "help") == 0) { | |
120 | explain(); | |
121 | return -1; | |
122 | } else { | |
123 | fprintf(stderr, "What is \"%s\"?\n", *argv); | |
124 | explain(); | |
125 | return -1; | |
126 | } | |
127 | argc--; argv++; | |
128 | } | |
129 | ||
c14f9d92 | 130 | tail = addattr_nest(n, 1024, TCA_OPTIONS); |
c3524efc ED |
131 | if (limit) |
132 | addattr_l(n, 1024, TCA_FQ_CODEL_LIMIT, &limit, sizeof(limit)); | |
133 | if (flows) | |
134 | addattr_l(n, 1024, TCA_FQ_CODEL_FLOWS, &flows, sizeof(flows)); | |
135 | if (quantum) | |
136 | addattr_l(n, 1024, TCA_FQ_CODEL_QUANTUM, &quantum, sizeof(quantum)); | |
137 | if (interval) | |
138 | addattr_l(n, 1024, TCA_FQ_CODEL_INTERVAL, &interval, sizeof(interval)); | |
139 | if (target) | |
140 | addattr_l(n, 1024, TCA_FQ_CODEL_TARGET, &target, sizeof(target)); | |
141 | if (ecn != -1) | |
142 | addattr_l(n, 1024, TCA_FQ_CODEL_ECN, &ecn, sizeof(ecn)); | |
df1c7d91 ED |
143 | if (ce_threshold != ~0U) |
144 | addattr_l(n, 1024, TCA_FQ_CODEL_CE_THRESHOLD, | |
145 | &ce_threshold, sizeof(ce_threshold)); | |
4de4b5ca ED |
146 | if (memory != ~0U) |
147 | addattr_l(n, 1024, TCA_FQ_CODEL_MEMORY_LIMIT, | |
148 | &memory, sizeof(memory)); | |
149 | ||
c14f9d92 | 150 | addattr_nest_end(n, tail); |
c3524efc ED |
151 | return 0; |
152 | } | |
153 | ||
154 | static int fq_codel_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) | |
155 | { | |
156 | struct rtattr *tb[TCA_FQ_CODEL_MAX + 1]; | |
32a121cb SH |
157 | unsigned int limit; |
158 | unsigned int flows; | |
159 | unsigned int interval; | |
160 | unsigned int target; | |
161 | unsigned int ecn; | |
162 | unsigned int quantum; | |
163 | unsigned int ce_threshold; | |
4de4b5ca | 164 | unsigned int memory_limit; |
32a121cb | 165 | |
c3524efc ED |
166 | SPRINT_BUF(b1); |
167 | ||
168 | if (opt == NULL) | |
169 | return 0; | |
170 | ||
171 | parse_rtattr_nested(tb, TCA_FQ_CODEL_MAX, opt); | |
172 | ||
173 | if (tb[TCA_FQ_CODEL_LIMIT] && | |
174 | RTA_PAYLOAD(tb[TCA_FQ_CODEL_LIMIT]) >= sizeof(__u32)) { | |
175 | limit = rta_getattr_u32(tb[TCA_FQ_CODEL_LIMIT]); | |
378ac491 | 176 | print_uint(PRINT_ANY, "limit", "limit %up ", limit); |
c3524efc ED |
177 | } |
178 | if (tb[TCA_FQ_CODEL_FLOWS] && | |
179 | RTA_PAYLOAD(tb[TCA_FQ_CODEL_FLOWS]) >= sizeof(__u32)) { | |
180 | flows = rta_getattr_u32(tb[TCA_FQ_CODEL_FLOWS]); | |
378ac491 | 181 | print_uint(PRINT_ANY, "flows", "flows %u ", flows); |
c3524efc ED |
182 | } |
183 | if (tb[TCA_FQ_CODEL_QUANTUM] && | |
184 | RTA_PAYLOAD(tb[TCA_FQ_CODEL_QUANTUM]) >= sizeof(__u32)) { | |
185 | quantum = rta_getattr_u32(tb[TCA_FQ_CODEL_QUANTUM]); | |
378ac491 | 186 | print_uint(PRINT_ANY, "quantum", "quantum %u ", quantum); |
c3524efc ED |
187 | } |
188 | if (tb[TCA_FQ_CODEL_TARGET] && | |
189 | RTA_PAYLOAD(tb[TCA_FQ_CODEL_TARGET]) >= sizeof(__u32)) { | |
190 | target = rta_getattr_u32(tb[TCA_FQ_CODEL_TARGET]); | |
378ac491 JP |
191 | print_uint(PRINT_JSON, "target", NULL, target); |
192 | print_string(PRINT_FP, NULL, "target %s ", | |
193 | sprint_time(target, b1)); | |
c3524efc | 194 | } |
df1c7d91 ED |
195 | if (tb[TCA_FQ_CODEL_CE_THRESHOLD] && |
196 | RTA_PAYLOAD(tb[TCA_FQ_CODEL_CE_THRESHOLD]) >= sizeof(__u32)) { | |
197 | ce_threshold = rta_getattr_u32(tb[TCA_FQ_CODEL_CE_THRESHOLD]); | |
378ac491 JP |
198 | print_uint(PRINT_JSON, "ce_threshold", NULL, ce_threshold); |
199 | print_string(PRINT_FP, NULL, "ce_threshold %s ", | |
200 | sprint_time(ce_threshold, b1)); | |
df1c7d91 | 201 | } |
c3524efc ED |
202 | if (tb[TCA_FQ_CODEL_INTERVAL] && |
203 | RTA_PAYLOAD(tb[TCA_FQ_CODEL_INTERVAL]) >= sizeof(__u32)) { | |
204 | interval = rta_getattr_u32(tb[TCA_FQ_CODEL_INTERVAL]); | |
378ac491 JP |
205 | print_uint(PRINT_JSON, "interval", NULL, interval); |
206 | print_string(PRINT_FP, NULL, "interval %s ", | |
207 | sprint_time(interval, b1)); | |
c3524efc | 208 | } |
4de4b5ca ED |
209 | if (tb[TCA_FQ_CODEL_MEMORY_LIMIT] && |
210 | RTA_PAYLOAD(tb[TCA_FQ_CODEL_MEMORY_LIMIT]) >= sizeof(__u32)) { | |
211 | memory_limit = rta_getattr_u32(tb[TCA_FQ_CODEL_MEMORY_LIMIT]); | |
378ac491 JP |
212 | print_uint(PRINT_JSON, "memory_limit", NULL, memory_limit); |
213 | print_string(PRINT_FP, NULL, "memory_limit %s ", | |
214 | sprint_size(memory_limit, b1)); | |
4de4b5ca | 215 | } |
c3524efc ED |
216 | if (tb[TCA_FQ_CODEL_ECN] && |
217 | RTA_PAYLOAD(tb[TCA_FQ_CODEL_ECN]) >= sizeof(__u32)) { | |
218 | ecn = rta_getattr_u32(tb[TCA_FQ_CODEL_ECN]); | |
219 | if (ecn) | |
378ac491 | 220 | print_bool(PRINT_ANY, "ecn", "ecn ", true); |
c3524efc ED |
221 | } |
222 | ||
223 | return 0; | |
224 | } | |
225 | ||
226 | static int fq_codel_print_xstats(struct qdisc_util *qu, FILE *f, | |
227 | struct rtattr *xstats) | |
228 | { | |
d17b136f | 229 | struct tc_fq_codel_xstats _st = {}, *st; |
32a121cb | 230 | |
c3524efc ED |
231 | SPRINT_BUF(b1); |
232 | ||
233 | if (xstats == NULL) | |
234 | return 0; | |
235 | ||
c3524efc | 236 | st = RTA_DATA(xstats); |
df1c7d91 | 237 | if (RTA_PAYLOAD(xstats) < sizeof(*st)) { |
df1c7d91 ED |
238 | memcpy(&_st, st, RTA_PAYLOAD(xstats)); |
239 | st = &_st; | |
240 | } | |
c3524efc | 241 | if (st->type == TCA_FQ_CODEL_XSTATS_QDISC) { |
997f2dc1 THJ |
242 | print_uint(PRINT_ANY, "maxpacket", " maxpacket %u", |
243 | st->qdisc_stats.maxpacket); | |
244 | print_uint(PRINT_ANY, "drop_overlimit", " drop_overlimit %u", | |
245 | st->qdisc_stats.drop_overlimit); | |
246 | print_uint(PRINT_ANY, "new_flow_count", " new_flow_count %u", | |
247 | st->qdisc_stats.new_flow_count); | |
248 | print_uint(PRINT_ANY, "ecn_mark", " ecn_mark %u", | |
c3524efc | 249 | st->qdisc_stats.ecn_mark); |
df1c7d91 | 250 | if (st->qdisc_stats.ce_mark) |
997f2dc1 THJ |
251 | print_uint(PRINT_ANY, "ce_mark", " ce_mark %u", |
252 | st->qdisc_stats.ce_mark); | |
4de4b5ca | 253 | if (st->qdisc_stats.memory_usage) |
997f2dc1 THJ |
254 | print_uint(PRINT_ANY, "memory_used", " memory_used %u", |
255 | st->qdisc_stats.memory_usage); | |
4de4b5ca | 256 | if (st->qdisc_stats.drop_overmemory) |
997f2dc1 THJ |
257 | print_uint(PRINT_ANY, "drop_overmemory", " drop_overmemory %u", |
258 | st->qdisc_stats.drop_overmemory); | |
259 | print_uint(PRINT_ANY, "new_flows_len", "\n new_flows_len %u", | |
260 | st->qdisc_stats.new_flows_len); | |
261 | print_uint(PRINT_ANY, "old_flows_len", " old_flows_len %u", | |
c3524efc ED |
262 | st->qdisc_stats.old_flows_len); |
263 | } | |
264 | if (st->type == TCA_FQ_CODEL_XSTATS_CLASS) { | |
997f2dc1 THJ |
265 | print_uint(PRINT_ANY, "deficit", " deficit %u", |
266 | st->class_stats.deficit); | |
267 | print_uint(PRINT_ANY, "count", " count %u", | |
268 | st->class_stats.count); | |
269 | print_uint(PRINT_ANY, "lastcount", " lastcount %u", | |
270 | st->class_stats.lastcount); | |
271 | print_uint(PRINT_JSON, "ldelay", NULL, | |
272 | st->class_stats.ldelay); | |
273 | print_string(PRINT_FP, NULL, " ldelay %s", | |
c3524efc ED |
274 | sprint_time(st->class_stats.ldelay, b1)); |
275 | if (st->class_stats.dropping) { | |
997f2dc1 | 276 | print_bool(PRINT_ANY, "dropping", " dropping", true); |
c3524efc | 277 | if (st->class_stats.drop_next < 0) |
997f2dc1 | 278 | print_string(PRINT_FP, NULL, " drop_next -%s", |
c3524efc | 279 | sprint_time(-st->class_stats.drop_next, b1)); |
997f2dc1 THJ |
280 | else { |
281 | print_uint(PRINT_JSON, "drop_next", NULL, | |
282 | st->class_stats.drop_next); | |
283 | print_string(PRINT_FP, NULL, " drop_next %s", | |
c3524efc | 284 | sprint_time(st->class_stats.drop_next, b1)); |
997f2dc1 | 285 | } |
c3524efc ED |
286 | } |
287 | } | |
288 | return 0; | |
289 | ||
290 | } | |
291 | ||
292 | struct qdisc_util fq_codel_qdisc_util = { | |
293 | .id = "fq_codel", | |
294 | .parse_qopt = fq_codel_parse_opt, | |
295 | .print_qopt = fq_codel_print_opt, | |
296 | .print_xstats = fq_codel_print_xstats, | |
297 | }; |