1
2
3#include <errno.h>
4#include <stdio.h>
5#include <linux/dcbnl.h>
6
7#include "dcb.h"
8#include "utils.h"
9
10static void dcb_ets_help_set(void)
11{
12 fprintf(stderr,
13 "Usage: dcb ets set dev STRING\n"
14 " [ willing { on | off } ]\n"
15 " [ { tc-tsa | reco-tc-tsa } TSA-MAP ]\n"
16 " [ { pg-bw | tc-bw | reco-tc-bw } BW-MAP ]\n"
17 " [ { prio-tc | reco-prio-tc } PRIO-MAP ]\n"
18 "\n"
19 " where TSA-MAP := [ TSA-MAP ] TSA-MAPPING\n"
20 " TSA-MAPPING := { all | TC }:{ strict | cbs | ets | vendor }\n"
21 " BW-MAP := [ BW-MAP ] BW-MAPPING\n"
22 " BW-MAPPING := { all | TC }:INTEGER\n"
23 " PRIO-MAP := [ PRIO-MAP ] PRIO-MAPPING\n"
24 " PRIO-MAPPING := { all | PRIO }:TC\n"
25 " TC := { 0 .. 7 }\n"
26 " PRIO := { 0 .. 7 }\n"
27 "\n"
28 );
29}
30
31static void dcb_ets_help_show(void)
32{
33 fprintf(stderr,
34 "Usage: dcb ets show dev STRING\n"
35 " [ willing ] [ ets-cap ] [ cbs ] [ tc-tsa ]\n"
36 " [ reco-tc-tsa ] [ pg-bw ] [ tc-bw ] [ reco-tc-bw ]\n"
37 " [ prio-tc ] [ reco-prio-tc ]\n"
38 "\n"
39 );
40}
41
42static void dcb_ets_help(void)
43{
44 fprintf(stderr,
45 "Usage: dcb ets help\n"
46 "\n"
47 );
48 dcb_ets_help_show();
49 dcb_ets_help_set();
50}
51
52static const char *const tsa_names[] = {
53 [IEEE_8021QAZ_TSA_STRICT] = "strict",
54 [IEEE_8021QAZ_TSA_CB_SHAPER] = "cbs",
55 [IEEE_8021QAZ_TSA_ETS] = "ets",
56 [IEEE_8021QAZ_TSA_VENDOR] = "vendor",
57};
58
59static int dcb_ets_parse_mapping_tc_tsa(__u32 key, char *value, void *data)
60{
61 __u8 tsa;
62 int ret;
63
64 tsa = parse_one_of("TSA", value, tsa_names, ARRAY_SIZE(tsa_names), &ret);
65 if (ret)
66 return ret;
67
68 return dcb_parse_mapping("TC", key, IEEE_8021QAZ_MAX_TCS - 1,
69 "TSA", tsa, -1U,
70 dcb_set_u8, data);
71}
72
73static int dcb_ets_parse_mapping_tc_bw(__u32 key, char *value, void *data)
74{
75 __u8 bw;
76
77 if (get_u8(&bw, value, 0))
78 return -EINVAL;
79
80 return dcb_parse_mapping("TC", key, IEEE_8021QAZ_MAX_TCS - 1,
81 "BW", bw, 100,
82 dcb_set_u8, data);
83}
84
85static int dcb_ets_parse_mapping_prio_tc(unsigned int key, char *value, void *data)
86{
87 __u8 tc;
88
89 if (get_u8(&tc, value, 0))
90 return -EINVAL;
91
92 return dcb_parse_mapping("PRIO", key, IEEE_8021QAZ_MAX_TCS - 1,
93 "TC", tc, IEEE_8021QAZ_MAX_TCS - 1,
94 dcb_set_u8, data);
95}
96
97static void dcb_print_array_tsa(const __u8 *array, size_t size)
98{
99 dcb_print_array_kw(array, size, tsa_names, ARRAY_SIZE(tsa_names));
100}
101
102static void dcb_ets_print_willing(const struct ieee_ets *ets)
103{
104 print_on_off(PRINT_ANY, "willing", "willing %s ", ets->willing);
105}
106
107static void dcb_ets_print_ets_cap(const struct ieee_ets *ets)
108{
109 print_uint(PRINT_ANY, "ets_cap", "ets-cap %d ", ets->ets_cap);
110}
111
112static void dcb_ets_print_cbs(const struct ieee_ets *ets)
113{
114 print_on_off(PRINT_ANY, "cbs", "cbs %s ", ets->cbs);
115}
116
117static void dcb_ets_print_tc_bw(const struct ieee_ets *ets)
118{
119 dcb_print_named_array("tc_bw", "tc-bw",
120 ets->tc_tx_bw, ARRAY_SIZE(ets->tc_tx_bw),
121 dcb_print_array_u8);
122}
123
124static void dcb_ets_print_pg_bw(const struct ieee_ets *ets)
125{
126 dcb_print_named_array("pg_bw", "pg-bw",
127 ets->tc_rx_bw, ARRAY_SIZE(ets->tc_rx_bw),
128 dcb_print_array_u8);
129}
130
131static void dcb_ets_print_tc_tsa(const struct ieee_ets *ets)
132{
133 dcb_print_named_array("tc_tsa", "tc-tsa",
134 ets->tc_tsa, ARRAY_SIZE(ets->tc_tsa),
135 dcb_print_array_tsa);
136}
137
138static void dcb_ets_print_prio_tc(const struct ieee_ets *ets)
139{
140 dcb_print_named_array("prio_tc", "prio-tc",
141 ets->prio_tc, ARRAY_SIZE(ets->prio_tc),
142 dcb_print_array_u8);
143}
144
145static void dcb_ets_print_reco_tc_bw(const struct ieee_ets *ets)
146{
147 dcb_print_named_array("reco_tc_bw", "reco-tc-bw",
148 ets->tc_reco_bw, ARRAY_SIZE(ets->tc_reco_bw),
149 dcb_print_array_u8);
150}
151
152static void dcb_ets_print_reco_tc_tsa(const struct ieee_ets *ets)
153{
154 dcb_print_named_array("reco_tc_tsa", "reco-tc-tsa",
155 ets->tc_reco_tsa, ARRAY_SIZE(ets->tc_reco_tsa),
156 dcb_print_array_tsa);
157}
158
159static void dcb_ets_print_reco_prio_tc(const struct ieee_ets *ets)
160{
161 dcb_print_named_array("reco_prio_tc", "reco-prio-tc",
162 ets->reco_prio_tc, ARRAY_SIZE(ets->reco_prio_tc),
163 dcb_print_array_u8);
164}
165
166static void dcb_ets_print(const struct ieee_ets *ets)
167{
168 dcb_ets_print_willing(ets);
169 dcb_ets_print_ets_cap(ets);
170 dcb_ets_print_cbs(ets);
171 print_nl();
172
173 dcb_ets_print_tc_bw(ets);
174 print_nl();
175
176 dcb_ets_print_pg_bw(ets);
177 print_nl();
178
179 dcb_ets_print_tc_tsa(ets);
180 print_nl();
181
182 dcb_ets_print_prio_tc(ets);
183 print_nl();
184
185 dcb_ets_print_reco_tc_bw(ets);
186 print_nl();
187
188 dcb_ets_print_reco_tc_tsa(ets);
189 print_nl();
190
191 dcb_ets_print_reco_prio_tc(ets);
192 print_nl();
193}
194
195static int dcb_ets_get(struct dcb *dcb, const char *dev, struct ieee_ets *ets)
196{
197 return dcb_get_attribute(dcb, dev, DCB_ATTR_IEEE_ETS, ets, sizeof(*ets));
198}
199
200static int dcb_ets_validate_bw(const __u8 bw[], const __u8 tsa[], const char *what)
201{
202 bool has_ets = false;
203 unsigned int total = 0;
204 unsigned int tc;
205
206 for (tc = 0; tc < IEEE_8021QAZ_MAX_TCS; tc++) {
207 if (tsa[tc] == IEEE_8021QAZ_TSA_ETS) {
208 has_ets = true;
209 break;
210 }
211 }
212
213
214
215
216
217
218 for (tc = 0; tc < IEEE_8021QAZ_MAX_TCS; tc++) {
219 if (bw[tc] > 100) {
220 fprintf(stderr, "%d%% for TC %d of %s is not a valid bandwidth percentage, expected 0..100%%\n",
221 bw[tc], tc, what);
222 return -EINVAL;
223 }
224 total += bw[tc];
225 }
226
227
228 if (total == 100)
229 return 0;
230
231
232
233
234
235
236
237 if (!has_ets && total == 0)
238 return 0;
239
240 fprintf(stderr, "Bandwidth percentages in %s sum to %d%%, expected %d%%\n",
241 what, total, has_ets ? 100 : 0);
242 return -EINVAL;
243}
244
245static int dcb_ets_set(struct dcb *dcb, const char *dev, const struct ieee_ets *ets)
246{
247
248
249
250 if (dcb_ets_validate_bw(ets->tc_tx_bw, ets->tc_tsa, "tc-bw") ||
251 dcb_ets_validate_bw(ets->tc_reco_bw, ets->tc_reco_tsa, "reco-tc-bw"))
252 return -EINVAL;
253
254 return dcb_set_attribute(dcb, dev, DCB_ATTR_IEEE_ETS, ets, sizeof(*ets));
255}
256
257static int dcb_cmd_ets_set(struct dcb *dcb, const char *dev, int argc, char **argv)
258{
259 struct ieee_ets ets;
260 int ret;
261
262 if (!argc) {
263 dcb_ets_help_set();
264 return 1;
265 }
266
267 ret = dcb_ets_get(dcb, dev, &ets);
268 if (ret)
269 return ret;
270
271 do {
272 if (matches(*argv, "help") == 0) {
273 dcb_ets_help_set();
274 return 0;
275 } else if (matches(*argv, "willing") == 0) {
276 NEXT_ARG();
277 ets.willing = parse_on_off("willing", *argv, &ret);
278 if (ret)
279 return ret;
280 } else if (matches(*argv, "tc-tsa") == 0) {
281 NEXT_ARG();
282 ret = parse_mapping(&argc, &argv, true, &dcb_ets_parse_mapping_tc_tsa,
283 ets.tc_tsa);
284 if (ret) {
285 fprintf(stderr, "Invalid tc-tsa mapping %s\n", *argv);
286 return ret;
287 }
288 continue;
289 } else if (matches(*argv, "reco-tc-tsa") == 0) {
290 NEXT_ARG();
291 ret = parse_mapping(&argc, &argv, true, &dcb_ets_parse_mapping_tc_tsa,
292 ets.tc_reco_tsa);
293 if (ret) {
294 fprintf(stderr, "Invalid reco-tc-tsa mapping %s\n", *argv);
295 return ret;
296 }
297 continue;
298 } else if (matches(*argv, "tc-bw") == 0) {
299 NEXT_ARG();
300 ret = parse_mapping(&argc, &argv, true, &dcb_ets_parse_mapping_tc_bw,
301 ets.tc_tx_bw);
302 if (ret) {
303 fprintf(stderr, "Invalid tc-bw mapping %s\n", *argv);
304 return ret;
305 }
306 continue;
307 } else if (matches(*argv, "pg-bw") == 0) {
308 NEXT_ARG();
309 ret = parse_mapping(&argc, &argv, true, &dcb_ets_parse_mapping_tc_bw,
310 ets.tc_rx_bw);
311 if (ret) {
312 fprintf(stderr, "Invalid pg-bw mapping %s\n", *argv);
313 return ret;
314 }
315 continue;
316 } else if (matches(*argv, "reco-tc-bw") == 0) {
317 NEXT_ARG();
318 ret = parse_mapping(&argc, &argv, true, &dcb_ets_parse_mapping_tc_bw,
319 ets.tc_reco_bw);
320 if (ret) {
321 fprintf(stderr, "Invalid reco-tc-bw mapping %s\n", *argv);
322 return ret;
323 }
324 continue;
325 } else if (matches(*argv, "prio-tc") == 0) {
326 NEXT_ARG();
327 ret = parse_mapping(&argc, &argv, true, &dcb_ets_parse_mapping_prio_tc,
328 ets.prio_tc);
329 if (ret) {
330 fprintf(stderr, "Invalid prio-tc mapping %s\n", *argv);
331 return ret;
332 }
333 continue;
334 } else if (matches(*argv, "reco-prio-tc") == 0) {
335 NEXT_ARG();
336 ret = parse_mapping(&argc, &argv, true, &dcb_ets_parse_mapping_prio_tc,
337 ets.reco_prio_tc);
338 if (ret) {
339 fprintf(stderr, "Invalid reco-prio-tc mapping %s\n", *argv);
340 return ret;
341 }
342 continue;
343 } else {
344 fprintf(stderr, "What is \"%s\"?\n", *argv);
345 dcb_ets_help_set();
346 return -EINVAL;
347 }
348
349 NEXT_ARG_FWD();
350 } while (argc > 0);
351
352 return dcb_ets_set(dcb, dev, &ets);
353}
354
355static int dcb_cmd_ets_show(struct dcb *dcb, const char *dev, int argc, char **argv)
356{
357 struct ieee_ets ets;
358 int ret;
359
360 ret = dcb_ets_get(dcb, dev, &ets);
361 if (ret)
362 return ret;
363
364 open_json_object(NULL);
365
366 if (!argc) {
367 dcb_ets_print(&ets);
368 goto out;
369 }
370
371 do {
372 if (matches(*argv, "help") == 0) {
373 dcb_ets_help_show();
374 return 0;
375 } else if (matches(*argv, "willing") == 0) {
376 dcb_ets_print_willing(&ets);
377 print_nl();
378 } else if (matches(*argv, "ets-cap") == 0) {
379 dcb_ets_print_ets_cap(&ets);
380 print_nl();
381 } else if (matches(*argv, "cbs") == 0) {
382 dcb_ets_print_cbs(&ets);
383 print_nl();
384 } else if (matches(*argv, "tc-tsa") == 0) {
385 dcb_ets_print_tc_tsa(&ets);
386 print_nl();
387 } else if (matches(*argv, "reco-tc-tsa") == 0) {
388 dcb_ets_print_reco_tc_tsa(&ets);
389 print_nl();
390 } else if (matches(*argv, "tc-bw") == 0) {
391 dcb_ets_print_tc_bw(&ets);
392 print_nl();
393 } else if (matches(*argv, "pg-bw") == 0) {
394 dcb_ets_print_pg_bw(&ets);
395 print_nl();
396 } else if (matches(*argv, "reco-tc-bw") == 0) {
397 dcb_ets_print_reco_tc_bw(&ets);
398 print_nl();
399 } else if (matches(*argv, "prio-tc") == 0) {
400 dcb_ets_print_prio_tc(&ets);
401 print_nl();
402 } else if (matches(*argv, "reco-prio-tc") == 0) {
403 dcb_ets_print_reco_prio_tc(&ets);
404 print_nl();
405 } else {
406 fprintf(stderr, "What is \"%s\"?\n", *argv);
407 dcb_ets_help_show();
408 return -EINVAL;
409 }
410
411 NEXT_ARG_FWD();
412 } while (argc > 0);
413
414out:
415 close_json_object();
416 return 0;
417}
418
419int dcb_cmd_ets(struct dcb *dcb, int argc, char **argv)
420{
421 if (!argc || matches(*argv, "help") == 0) {
422 dcb_ets_help();
423 return 0;
424 } else if (matches(*argv, "show") == 0) {
425 NEXT_ARG_FWD();
426 return dcb_cmd_parse_dev(dcb, argc, argv, dcb_cmd_ets_show, dcb_ets_help_show);
427 } else if (matches(*argv, "set") == 0) {
428 NEXT_ARG_FWD();
429 return dcb_cmd_parse_dev(dcb, argc, argv, dcb_cmd_ets_set, dcb_ets_help_set);
430 } else {
431 fprintf(stderr, "What is \"%s\"?\n", *argv);
432 dcb_ets_help();
433 return -EINVAL;
434 }
435}
436