]>
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"); | |
4733b18a | 53 | fprintf(stderr, " [ target TIME ] [ interval TIME ]\n"); |
c3524efc | 54 | fprintf(stderr, " [ quantum BYTES ] [ [no]ecn ]\n"); |
df1c7d91 | 55 | fprintf(stderr, " [ ce_threshold TIME ]\n"); |
c3524efc ED |
56 | } |
57 | ||
58 | static int fq_codel_parse_opt(struct qdisc_util *qu, int argc, char **argv, | |
927e3cfb | 59 | struct nlmsghdr *n, const char *dev) |
c3524efc | 60 | { |
32a121cb SH |
61 | unsigned int limit = 0; |
62 | unsigned int flows = 0; | |
63 | unsigned int target = 0; | |
64 | unsigned int interval = 0; | |
65 | unsigned int quantum = 0; | |
66 | unsigned int ce_threshold = ~0U; | |
4de4b5ca | 67 | unsigned int memory = ~0U; |
c3524efc ED |
68 | int ecn = -1; |
69 | struct rtattr *tail; | |
70 | ||
71 | while (argc > 0) { | |
72 | if (strcmp(*argv, "limit") == 0) { | |
73 | NEXT_ARG(); | |
74 | if (get_unsigned(&limit, *argv, 0)) { | |
75 | fprintf(stderr, "Illegal \"limit\"\n"); | |
76 | return -1; | |
77 | } | |
78 | } else if (strcmp(*argv, "flows") == 0) { | |
79 | NEXT_ARG(); | |
80 | if (get_unsigned(&flows, *argv, 0)) { | |
81 | fprintf(stderr, "Illegal \"flows\"\n"); | |
82 | return -1; | |
83 | } | |
84 | } else if (strcmp(*argv, "quantum") == 0) { | |
85 | NEXT_ARG(); | |
86 | if (get_unsigned(&quantum, *argv, 0)) { | |
87 | fprintf(stderr, "Illegal \"quantum\"\n"); | |
88 | return -1; | |
89 | } | |
90 | } else if (strcmp(*argv, "target") == 0) { | |
91 | NEXT_ARG(); | |
92 | if (get_time(&target, *argv)) { | |
93 | fprintf(stderr, "Illegal \"target\"\n"); | |
94 | return -1; | |
95 | } | |
df1c7d91 ED |
96 | } else if (strcmp(*argv, "ce_threshold") == 0) { |
97 | NEXT_ARG(); | |
98 | if (get_time(&ce_threshold, *argv)) { | |
99 | fprintf(stderr, "Illegal \"ce_threshold\"\n"); | |
100 | return -1; | |
101 | } | |
4de4b5ca ED |
102 | } else if (strcmp(*argv, "memory_limit") == 0) { |
103 | NEXT_ARG(); | |
104 | if (get_size(&memory, *argv)) { | |
105 | fprintf(stderr, "Illegal \"memory_limit\"\n"); | |
106 | return -1; | |
107 | } | |
c3524efc ED |
108 | } else if (strcmp(*argv, "interval") == 0) { |
109 | NEXT_ARG(); | |
110 | if (get_time(&interval, *argv)) { | |
111 | fprintf(stderr, "Illegal \"interval\"\n"); | |
112 | return -1; | |
113 | } | |
114 | } else if (strcmp(*argv, "ecn") == 0) { | |
115 | ecn = 1; | |
116 | } else if (strcmp(*argv, "noecn") == 0) { | |
117 | ecn = 0; | |
118 | } else if (strcmp(*argv, "help") == 0) { | |
119 | explain(); | |
120 | return -1; | |
121 | } else { | |
122 | fprintf(stderr, "What is \"%s\"?\n", *argv); | |
123 | explain(); | |
124 | return -1; | |
125 | } | |
126 | argc--; argv++; | |
127 | } | |
128 | ||
129 | tail = NLMSG_TAIL(n); | |
130 | addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); | |
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 | ||
c3524efc ED |
150 | tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail; |
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]); | |
176 | fprintf(f, "limit %up ", limit); | |
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]); | |
181 | fprintf(f, "flows %u ", flows); | |
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]); | |
186 | fprintf(f, "quantum %u ", quantum); | |
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]); | |
191 | fprintf(f, "target %s ", sprint_time(target, b1)); | |
192 | } | |
df1c7d91 ED |
193 | if (tb[TCA_FQ_CODEL_CE_THRESHOLD] && |
194 | RTA_PAYLOAD(tb[TCA_FQ_CODEL_CE_THRESHOLD]) >= sizeof(__u32)) { | |
195 | ce_threshold = rta_getattr_u32(tb[TCA_FQ_CODEL_CE_THRESHOLD]); | |
196 | fprintf(f, "ce_threshold %s ", sprint_time(ce_threshold, b1)); | |
197 | } | |
c3524efc ED |
198 | if (tb[TCA_FQ_CODEL_INTERVAL] && |
199 | RTA_PAYLOAD(tb[TCA_FQ_CODEL_INTERVAL]) >= sizeof(__u32)) { | |
200 | interval = rta_getattr_u32(tb[TCA_FQ_CODEL_INTERVAL]); | |
201 | fprintf(f, "interval %s ", sprint_time(interval, b1)); | |
202 | } | |
4de4b5ca ED |
203 | if (tb[TCA_FQ_CODEL_MEMORY_LIMIT] && |
204 | RTA_PAYLOAD(tb[TCA_FQ_CODEL_MEMORY_LIMIT]) >= sizeof(__u32)) { | |
205 | memory_limit = rta_getattr_u32(tb[TCA_FQ_CODEL_MEMORY_LIMIT]); | |
206 | ||
207 | fprintf(f, "memory_limit %s ", sprint_size(memory_limit, b1)); | |
208 | } | |
c3524efc ED |
209 | if (tb[TCA_FQ_CODEL_ECN] && |
210 | RTA_PAYLOAD(tb[TCA_FQ_CODEL_ECN]) >= sizeof(__u32)) { | |
211 | ecn = rta_getattr_u32(tb[TCA_FQ_CODEL_ECN]); | |
212 | if (ecn) | |
213 | fprintf(f, "ecn "); | |
214 | } | |
215 | ||
216 | return 0; | |
217 | } | |
218 | ||
219 | static int fq_codel_print_xstats(struct qdisc_util *qu, FILE *f, | |
220 | struct rtattr *xstats) | |
221 | { | |
d17b136f | 222 | struct tc_fq_codel_xstats _st = {}, *st; |
32a121cb | 223 | |
c3524efc ED |
224 | SPRINT_BUF(b1); |
225 | ||
226 | if (xstats == NULL) | |
227 | return 0; | |
228 | ||
c3524efc | 229 | st = RTA_DATA(xstats); |
df1c7d91 | 230 | if (RTA_PAYLOAD(xstats) < sizeof(*st)) { |
df1c7d91 ED |
231 | memcpy(&_st, st, RTA_PAYLOAD(xstats)); |
232 | st = &_st; | |
233 | } | |
c3524efc ED |
234 | if (st->type == TCA_FQ_CODEL_XSTATS_QDISC) { |
235 | fprintf(f, " maxpacket %u drop_overlimit %u new_flow_count %u ecn_mark %u", | |
236 | st->qdisc_stats.maxpacket, | |
237 | st->qdisc_stats.drop_overlimit, | |
238 | st->qdisc_stats.new_flow_count, | |
239 | st->qdisc_stats.ecn_mark); | |
df1c7d91 ED |
240 | if (st->qdisc_stats.ce_mark) |
241 | fprintf(f, " ce_mark %u", st->qdisc_stats.ce_mark); | |
4de4b5ca ED |
242 | if (st->qdisc_stats.memory_usage) |
243 | fprintf(f, " memory_used %u", st->qdisc_stats.memory_usage); | |
244 | if (st->qdisc_stats.drop_overmemory) | |
245 | fprintf(f, " drop_overmemory %u", st->qdisc_stats.drop_overmemory); | |
c3524efc ED |
246 | fprintf(f, "\n new_flows_len %u old_flows_len %u", |
247 | st->qdisc_stats.new_flows_len, | |
248 | st->qdisc_stats.old_flows_len); | |
249 | } | |
250 | if (st->type == TCA_FQ_CODEL_XSTATS_CLASS) { | |
251 | fprintf(f, " deficit %d count %u lastcount %u ldelay %s", | |
252 | st->class_stats.deficit, | |
253 | st->class_stats.count, | |
254 | st->class_stats.lastcount, | |
255 | sprint_time(st->class_stats.ldelay, b1)); | |
256 | if (st->class_stats.dropping) { | |
257 | fprintf(f, " dropping"); | |
258 | if (st->class_stats.drop_next < 0) | |
259 | fprintf(f, " drop_next -%s", | |
260 | sprint_time(-st->class_stats.drop_next, b1)); | |
261 | else | |
262 | fprintf(f, " drop_next %s", | |
263 | sprint_time(st->class_stats.drop_next, b1)); | |
264 | } | |
265 | } | |
266 | return 0; | |
267 | ||
268 | } | |
269 | ||
270 | struct qdisc_util fq_codel_qdisc_util = { | |
271 | .id = "fq_codel", | |
272 | .parse_qopt = fq_codel_parse_opt, | |
273 | .print_qopt = fq_codel_print_opt, | |
274 | .print_xstats = fq_codel_print_xstats, | |
275 | }; |