]> git.proxmox.com Git - mirror_iproute2.git/blame - tc/q_ets.c
man: dcb-ets: Remove an unnecessary empty line
[mirror_iproute2.git] / tc / q_ets.c
CommitLineData
d2773f12
PM
1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2
3/*
4 * Enhanced Transmission Selection - 802.1Qaz-based Qdisc
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 (nbands < 1) {
151 fprintf(stderr, "The number of \"bands\" must be >= 1\n");
152 explain();
153 return -1;
154 }
155 if (nstrict + nquanta > nbands) {
156 fprintf(stderr, "Not enough total bands to cover all the strict bands and quanta\n");
157 explain();
158 return -1;
159 }
160 for (tmp = 0; tmp < nprio; tmp++) {
161 if (priomap[tmp] >= nbands) {
162 fprintf(stderr, "\"priomap\" element is out of bounds\n");
163 return -1;
164 }
165 }
166
167 tail = addattr_nest(n, 1024, TCA_OPTIONS | NLA_F_NESTED);
168 addattr_l(n, 1024, TCA_ETS_NBANDS, &nbands, sizeof(nbands));
169 if (nstrict)
170 addattr_l(n, 1024, TCA_ETS_NSTRICT, &nstrict, sizeof(nstrict));
171 if (nquanta) {
172 nest = addattr_nest(n, 1024, TCA_ETS_QUANTA | NLA_F_NESTED);
173 for (tmp = 0; tmp < nquanta; tmp++)
174 addattr_l(n, 1024, TCA_ETS_QUANTA_BAND,
175 &quanta[tmp], sizeof(quanta[0]));
176 addattr_nest_end(n, nest);
177 }
178 if (nprio) {
179 nest = addattr_nest(n, 1024, TCA_ETS_PRIOMAP | NLA_F_NESTED);
180 for (tmp = 0; tmp < nprio; tmp++)
181 addattr_l(n, 1024, TCA_ETS_PRIOMAP_BAND,
182 &priomap[tmp], sizeof(priomap[0]));
183 addattr_nest_end(n, nest);
184 }
185 addattr_nest_end(n, tail);
186
187 return 0;
188}
189
190static int ets_parse_copt(struct qdisc_util *qu, int argc, char **argv,
191 struct nlmsghdr *n, const char *dev)
192{
193 unsigned int quantum = 0;
194 struct rtattr *tail;
195
196 while (argc > 0) {
197 if (strcmp(*argv, "quantum") == 0) {
198 if (quantum) {
199 fprintf(stderr, "Duplicate \"quantum\"\n");
200 return -1;
201 }
202 NEXT_ARG();
203 quantum = parse_quantum(*argv);
204 if (!quantum)
205 return -1;
206 } else if (strcmp(*argv, "help") == 0) {
207 cexplain();
208 return -1;
209 } else {
210 fprintf(stderr, "What is \"%s\"?\n", *argv);
211 cexplain();
212 return -1;
213 }
214 argc--; argv++;
215 }
216
217 tail = addattr_nest(n, 1024, TCA_OPTIONS | NLA_F_NESTED);
218 if (quantum)
219 addattr_l(n, 1024, TCA_ETS_QUANTA_BAND, &quantum,
220 sizeof(quantum));
221 addattr_nest_end(n, tail);
222
223 return 0;
224}
225
226static int ets_print_opt_quanta(struct rtattr *opt)
227{
228 int len = RTA_PAYLOAD(opt);
229 unsigned int offset;
230
231 open_json_array(PRINT_ANY, "quanta");
232 for (offset = 0; offset < len; ) {
233 struct rtattr *tb[TCA_ETS_MAX + 1] = {NULL};
234 struct rtattr *attr;
235 __u32 quantum;
236
237 attr = RTA_DATA(opt) + offset;
238 parse_rtattr(tb, TCA_ETS_MAX, attr, len - offset);
239 offset += RTA_LENGTH(RTA_PAYLOAD(attr));
240
241 if (!tb[TCA_ETS_QUANTA_BAND]) {
242 fprintf(stderr, "No ETS band quantum\n");
243 return -1;
244 }
245
246 quantum = rta_getattr_u32(tb[TCA_ETS_QUANTA_BAND]);
247 print_uint(PRINT_ANY, NULL, " %u", quantum);
248
249 }
250 close_json_array(PRINT_ANY, " ");
251
252 return 0;
253}
254
255static int ets_print_opt_priomap(struct rtattr *opt)
256{
257 int len = RTA_PAYLOAD(opt);
258 unsigned int offset;
259
260 open_json_array(PRINT_ANY, "priomap");
261 for (offset = 0; offset < len; ) {
262 struct rtattr *tb[TCA_ETS_MAX + 1] = {NULL};
263 struct rtattr *attr;
264 __u8 band;
265
266 attr = RTA_DATA(opt) + offset;
267 parse_rtattr(tb, TCA_ETS_MAX, attr, len - offset);
268 offset += RTA_LENGTH(RTA_PAYLOAD(attr)) + 3 /* padding */;
269
270 if (!tb[TCA_ETS_PRIOMAP_BAND]) {
271 fprintf(stderr, "No ETS priomap band\n");
272 return -1;
273 }
274
275 band = rta_getattr_u8(tb[TCA_ETS_PRIOMAP_BAND]);
276 print_uint(PRINT_ANY, NULL, " %u", band);
277
278 }
279 close_json_array(PRINT_ANY, " ");
280
281 return 0;
282}
283
284static int ets_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
285{
286 struct rtattr *tb[TCA_ETS_MAX + 1];
287 __u8 nbands;
288 __u8 nstrict;
289 int err;
290
291 if (opt == NULL)
292 return 0;
293
294 parse_rtattr_nested(tb, TCA_ETS_MAX, opt);
295
296 if (!tb[TCA_ETS_NBANDS] || !tb[TCA_ETS_PRIOMAP]) {
297 fprintf(stderr, "Incomplete ETS options\n");
298 return -1;
299 }
300
301 nbands = rta_getattr_u8(tb[TCA_ETS_NBANDS]);
302 print_uint(PRINT_ANY, "bands", "bands %u ", nbands);
303
304 if (tb[TCA_ETS_NSTRICT]) {
305 nstrict = rta_getattr_u8(tb[TCA_ETS_NSTRICT]);
306 print_uint(PRINT_ANY, "strict", "strict %u ", nstrict);
307 }
308
309 if (tb[TCA_ETS_QUANTA]) {
310 err = ets_print_opt_quanta(tb[TCA_ETS_QUANTA]);
311 if (err)
312 return err;
313 }
314
315 return ets_print_opt_priomap(tb[TCA_ETS_PRIOMAP]);
316}
317
318static int ets_print_copt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
319{
320 struct rtattr *tb[TCA_ETS_MAX + 1];
321 __u32 quantum;
322
323 if (opt == NULL)
324 return 0;
325
326 parse_rtattr_nested(tb, TCA_ETS_MAX, opt);
327
328 if (tb[TCA_ETS_QUANTA_BAND]) {
329 quantum = rta_getattr_u32(tb[TCA_ETS_QUANTA_BAND]);
330 print_uint(PRINT_ANY, "quantum", "quantum %u ", quantum);
331 }
332
333 return 0;
334}
335
336struct qdisc_util ets_qdisc_util = {
337 .id = "ets",
338 .parse_qopt = ets_parse_opt,
339 .parse_copt = ets_parse_copt,
340 .print_qopt = ets_print_opt,
341 .print_copt = ets_print_copt,
342};