1
2
3
4
5
6
7#include <stdio.h>
8#include <stdlib.h>
9#include <unistd.h>
10#include <fcntl.h>
11#include <sys/socket.h>
12#include <netinet/in.h>
13#include <arpa/inet.h>
14#include <string.h>
15
16#include "utils.h"
17#include "tc_util.h"
18
19static void explain(void)
20{
21 fprintf(stderr, "Usage: ... ets [bands NUMBER] [strict NUMBER] [quanta Q1 Q2...] [priomap P1 P2...]\n");
22}
23
24static void cexplain(void)
25{
26 fprintf(stderr, "Usage: ... ets [quantum Q1]\n");
27}
28
29static unsigned int parse_quantum(const char *arg)
30{
31 unsigned int quantum;
32
33 if (get_unsigned(&quantum, arg, 10)) {
34 fprintf(stderr, "Illegal \"quanta\" element\n");
35 return 0;
36 }
37 if (!quantum)
38 fprintf(stderr, "\"quanta\" must be > 0\n");
39 return quantum;
40}
41
42static int parse_nbands(const char *arg, __u8 *pnbands, const char *what)
43{
44 unsigned int tmp;
45
46 if (get_unsigned(&tmp, arg, 10)) {
47 fprintf(stderr, "Illegal \"%s\"\n", what);
48 return -1;
49 }
50 if (tmp > TCQ_ETS_MAX_BANDS) {
51 fprintf(stderr, "The number of \"%s\" must be <= %d\n",
52 what, TCQ_ETS_MAX_BANDS);
53 return -1;
54 }
55
56 *pnbands = tmp;
57 return 0;
58}
59
60static int ets_parse_opt(struct qdisc_util *qu, int argc, char **argv,
61 struct nlmsghdr *n, const char *dev)
62{
63 __u8 nbands = 0;
64 __u8 nstrict = 0;
65 bool quanta_mode = false;
66 unsigned int nquanta = 0;
67 __u32 quanta[TCQ_ETS_MAX_BANDS];
68 bool priomap_mode = false;
69 unsigned int nprio = 0;
70 __u8 priomap[TC_PRIO_MAX + 1];
71 unsigned int tmp;
72 struct rtattr *tail, *nest;
73
74 while (argc > 0) {
75 if (strcmp(*argv, "bands") == 0) {
76 if (nbands) {
77 fprintf(stderr, "Duplicate \"bands\"\n");
78 return -1;
79 }
80 NEXT_ARG();
81 if (parse_nbands(*argv, &nbands, "bands"))
82 return -1;
83 priomap_mode = quanta_mode = false;
84 } else if (strcmp(*argv, "strict") == 0) {
85 if (nstrict) {
86 fprintf(stderr, "Duplicate \"strict\"\n");
87 return -1;
88 }
89 NEXT_ARG();
90 if (parse_nbands(*argv, &nstrict, "strict"))
91 return -1;
92 priomap_mode = quanta_mode = false;
93 } else if (strcmp(*argv, "quanta") == 0) {
94 if (nquanta) {
95 fprintf(stderr, "Duplicate \"quanta\"\n");
96 return -1;
97 }
98 NEXT_ARG();
99 priomap_mode = false;
100 quanta_mode = true;
101 goto parse_quantum;
102 } else if (strcmp(*argv, "priomap") == 0) {
103 if (nprio) {
104 fprintf(stderr, "Duplicate \"priomap\"\n");
105 return -1;
106 }
107 NEXT_ARG();
108 priomap_mode = true;
109 quanta_mode = false;
110 goto parse_priomap;
111 } else if (strcmp(*argv, "help") == 0) {
112 explain();
113 return -1;
114 } else if (quanta_mode) {
115 unsigned int quantum;
116
117parse_quantum:
118 quantum = parse_quantum(*argv);
119 if (!quantum)
120 return -1;
121 quanta[nquanta++] = quantum;
122 } else if (priomap_mode) {
123 unsigned int band;
124
125parse_priomap:
126 if (get_unsigned(&band, *argv, 10)) {
127 fprintf(stderr, "Illegal \"priomap\" element\n");
128 return -1;
129 }
130 if (nprio > TC_PRIO_MAX) {
131 fprintf(stderr, "\"priomap\" index cannot be higher than %u\n", TC_PRIO_MAX);
132 return -1;
133 }
134 priomap[nprio++] = band;
135 } else {
136 fprintf(stderr, "What is \"%s\"?\n", *argv);
137 explain();
138 return -1;
139 }
140 argc--; argv++;
141 }
142
143 if (!nbands)
144 nbands = nquanta + nstrict;
145 if (!nbands) {
146 fprintf(stderr, "One of \"bands\", \"quanta\" or \"strict\" needs to be specified\n");
147 explain();
148 return -1;
149 }
150 if (nstrict + nquanta > nbands) {
151 fprintf(stderr, "Not enough total bands to cover all the strict bands and quanta\n");
152 explain();
153 return -1;
154 }
155 for (tmp = 0; tmp < nprio; tmp++) {
156 if (priomap[tmp] >= nbands) {
157 fprintf(stderr, "\"priomap\" element is out of bounds\n");
158 return -1;
159 }
160 }
161
162 tail = addattr_nest(n, 1024, TCA_OPTIONS | NLA_F_NESTED);
163 addattr_l(n, 1024, TCA_ETS_NBANDS, &nbands, sizeof(nbands));
164 if (nstrict)
165 addattr_l(n, 1024, TCA_ETS_NSTRICT, &nstrict, sizeof(nstrict));
166 if (nquanta) {
167 nest = addattr_nest(n, 1024, TCA_ETS_QUANTA | NLA_F_NESTED);
168 for (tmp = 0; tmp < nquanta; tmp++)
169 addattr_l(n, 1024, TCA_ETS_QUANTA_BAND,
170 &quanta[tmp], sizeof(quanta[0]));
171 addattr_nest_end(n, nest);
172 }
173 if (nprio) {
174 nest = addattr_nest(n, 1024, TCA_ETS_PRIOMAP | NLA_F_NESTED);
175 for (tmp = 0; tmp < nprio; tmp++)
176 addattr_l(n, 1024, TCA_ETS_PRIOMAP_BAND,
177 &priomap[tmp], sizeof(priomap[0]));
178 addattr_nest_end(n, nest);
179 }
180 addattr_nest_end(n, tail);
181
182 return 0;
183}
184
185static int ets_parse_copt(struct qdisc_util *qu, int argc, char **argv,
186 struct nlmsghdr *n, const char *dev)
187{
188 unsigned int quantum = 0;
189 struct rtattr *tail;
190
191 while (argc > 0) {
192 if (strcmp(*argv, "quantum") == 0) {
193 if (quantum) {
194 fprintf(stderr, "Duplicate \"quantum\"\n");
195 return -1;
196 }
197 NEXT_ARG();
198 quantum = parse_quantum(*argv);
199 if (!quantum)
200 return -1;
201 } else if (strcmp(*argv, "help") == 0) {
202 cexplain();
203 return -1;
204 } else {
205 fprintf(stderr, "What is \"%s\"?\n", *argv);
206 cexplain();
207 return -1;
208 }
209 argc--; argv++;
210 }
211
212 tail = addattr_nest(n, 1024, TCA_OPTIONS | NLA_F_NESTED);
213 if (quantum)
214 addattr_l(n, 1024, TCA_ETS_QUANTA_BAND, &quantum,
215 sizeof(quantum));
216 addattr_nest_end(n, tail);
217
218 return 0;
219}
220
221static int ets_print_opt_quanta(struct rtattr *opt)
222{
223 int len = RTA_PAYLOAD(opt);
224 unsigned int offset;
225
226 open_json_array(PRINT_ANY, "quanta");
227 for (offset = 0; offset < len; ) {
228 struct rtattr *tb[TCA_ETS_MAX + 1] = {NULL};
229 struct rtattr *attr;
230 __u32 quantum;
231
232 attr = RTA_DATA(opt) + offset;
233 parse_rtattr(tb, TCA_ETS_MAX, attr, len - offset);
234 offset += RTA_LENGTH(RTA_PAYLOAD(attr));
235
236 if (!tb[TCA_ETS_QUANTA_BAND]) {
237 fprintf(stderr, "No ETS band quantum\n");
238 return -1;
239 }
240
241 quantum = rta_getattr_u32(tb[TCA_ETS_QUANTA_BAND]);
242 print_uint(PRINT_ANY, NULL, " %u", quantum);
243
244 }
245 close_json_array(PRINT_ANY, " ");
246
247 return 0;
248}
249
250static int ets_print_opt_priomap(struct rtattr *opt)
251{
252 int len = RTA_PAYLOAD(opt);
253 unsigned int offset;
254
255 open_json_array(PRINT_ANY, "priomap");
256 for (offset = 0; offset < len; ) {
257 struct rtattr *tb[TCA_ETS_MAX + 1] = {NULL};
258 struct rtattr *attr;
259 __u8 band;
260
261 attr = RTA_DATA(opt) + offset;
262 parse_rtattr(tb, TCA_ETS_MAX, attr, len - offset);
263 offset += RTA_LENGTH(RTA_PAYLOAD(attr)) + 3 ;
264
265 if (!tb[TCA_ETS_PRIOMAP_BAND]) {
266 fprintf(stderr, "No ETS priomap band\n");
267 return -1;
268 }
269
270 band = rta_getattr_u8(tb[TCA_ETS_PRIOMAP_BAND]);
271 print_uint(PRINT_ANY, NULL, " %u", band);
272
273 }
274 close_json_array(PRINT_ANY, " ");
275
276 return 0;
277}
278
279static int ets_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
280{
281 struct rtattr *tb[TCA_ETS_MAX + 1];
282 __u8 nbands;
283 __u8 nstrict;
284 int err;
285
286 if (opt == NULL)
287 return 0;
288
289 parse_rtattr_nested(tb, TCA_ETS_MAX, opt);
290
291 if (!tb[TCA_ETS_NBANDS] || !tb[TCA_ETS_PRIOMAP]) {
292 fprintf(stderr, "Incomplete ETS options\n");
293 return -1;
294 }
295
296 nbands = rta_getattr_u8(tb[TCA_ETS_NBANDS]);
297 print_uint(PRINT_ANY, "bands", "bands %u ", nbands);
298
299 if (tb[TCA_ETS_NSTRICT]) {
300 nstrict = rta_getattr_u8(tb[TCA_ETS_NSTRICT]);
301 print_uint(PRINT_ANY, "strict", "strict %u ", nstrict);
302 }
303
304 if (tb[TCA_ETS_QUANTA]) {
305 err = ets_print_opt_quanta(tb[TCA_ETS_QUANTA]);
306 if (err)
307 return err;
308 }
309
310 return ets_print_opt_priomap(tb[TCA_ETS_PRIOMAP]);
311}
312
313static int ets_print_copt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
314{
315 struct rtattr *tb[TCA_ETS_MAX + 1];
316 __u32 quantum;
317
318 if (opt == NULL)
319 return 0;
320
321 parse_rtattr_nested(tb, TCA_ETS_MAX, opt);
322
323 if (tb[TCA_ETS_QUANTA_BAND]) {
324 quantum = rta_getattr_u32(tb[TCA_ETS_QUANTA_BAND]);
325 print_uint(PRINT_ANY, "quantum", "quantum %u ", quantum);
326 }
327
328 return 0;
329}
330
331struct qdisc_util ets_qdisc_util = {
332 .id = "ets",
333 .parse_qopt = ets_parse_opt,
334 .parse_copt = ets_parse_copt,
335 .print_qopt = ets_print_opt,
336 .print_copt = ets_print_copt,
337};
338