1 // SPDX-License-Identifier: GPL-2.0+
5 #include <linux/dcbnl.h>
10 static void dcb_ets_help_set(void)
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"
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"
26 " PRIO := { 0 .. 7 }\n"
31 static void dcb_ets_help_show(void)
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"
42 static void dcb_ets_help(void)
45 "Usage: dcb ets help\n"
52 static 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",
59 static int dcb_ets_parse_mapping_tc_tsa(__u32 key
, char *value
, void *data
)
64 tsa
= parse_one_of("TSA", value
, tsa_names
, ARRAY_SIZE(tsa_names
), &ret
);
68 return dcb_parse_mapping("TC", key
, IEEE_8021QAZ_MAX_TCS
- 1,
73 static int dcb_ets_parse_mapping_tc_bw(__u32 key
, char *value
, void *data
)
77 if (get_u8(&bw
, value
, 0))
80 return dcb_parse_mapping("TC", key
, IEEE_8021QAZ_MAX_TCS
- 1,
85 static int dcb_ets_parse_mapping_prio_tc(unsigned int key
, char *value
, void *data
)
89 if (get_u8(&tc
, value
, 0))
92 return dcb_parse_mapping("PRIO", key
, IEEE_8021QAZ_MAX_TCS
- 1,
93 "TC", tc
, IEEE_8021QAZ_MAX_TCS
- 1,
97 static void dcb_print_array_tsa(const __u8
*array
, size_t size
)
99 dcb_print_array_kw(array
, size
, tsa_names
, ARRAY_SIZE(tsa_names
));
102 static void dcb_ets_print_willing(const struct ieee_ets
*ets
)
104 print_on_off(PRINT_ANY
, "willing", "willing %s ", ets
->willing
);
107 static void dcb_ets_print_ets_cap(const struct ieee_ets
*ets
)
109 print_uint(PRINT_ANY
, "ets_cap", "ets-cap %d ", ets
->ets_cap
);
112 static void dcb_ets_print_cbs(const struct ieee_ets
*ets
)
114 print_on_off(PRINT_ANY
, "cbs", "cbs %s ", ets
->cbs
);
117 static void dcb_ets_print_tc_bw(const struct ieee_ets
*ets
)
119 dcb_print_named_array("tc_bw", "tc-bw",
120 ets
->tc_tx_bw
, ARRAY_SIZE(ets
->tc_tx_bw
),
124 static void dcb_ets_print_pg_bw(const struct ieee_ets
*ets
)
126 dcb_print_named_array("pg_bw", "pg-bw",
127 ets
->tc_rx_bw
, ARRAY_SIZE(ets
->tc_rx_bw
),
131 static void dcb_ets_print_tc_tsa(const struct ieee_ets
*ets
)
133 dcb_print_named_array("tc_tsa", "tc-tsa",
134 ets
->tc_tsa
, ARRAY_SIZE(ets
->tc_tsa
),
135 dcb_print_array_tsa
);
138 static void dcb_ets_print_prio_tc(const struct ieee_ets
*ets
)
140 dcb_print_named_array("prio_tc", "prio-tc",
141 ets
->prio_tc
, ARRAY_SIZE(ets
->prio_tc
),
145 static void dcb_ets_print_reco_tc_bw(const struct ieee_ets
*ets
)
147 dcb_print_named_array("reco_tc_bw", "reco-tc-bw",
148 ets
->tc_reco_bw
, ARRAY_SIZE(ets
->tc_reco_bw
),
152 static void dcb_ets_print_reco_tc_tsa(const struct ieee_ets
*ets
)
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
);
159 static void dcb_ets_print_reco_prio_tc(const struct ieee_ets
*ets
)
161 dcb_print_named_array("reco_prio_tc", "reco-prio-tc",
162 ets
->reco_prio_tc
, ARRAY_SIZE(ets
->reco_prio_tc
),
166 static void dcb_ets_print(const struct ieee_ets
*ets
)
168 dcb_ets_print_willing(ets
);
169 dcb_ets_print_ets_cap(ets
);
170 dcb_ets_print_cbs(ets
);
173 dcb_ets_print_tc_bw(ets
);
176 dcb_ets_print_pg_bw(ets
);
179 dcb_ets_print_tc_tsa(ets
);
182 dcb_ets_print_prio_tc(ets
);
185 dcb_ets_print_reco_tc_bw(ets
);
188 dcb_ets_print_reco_tc_tsa(ets
);
191 dcb_ets_print_reco_prio_tc(ets
);
195 static int dcb_ets_get(struct dcb
*dcb
, const char *dev
, struct ieee_ets
*ets
)
197 return dcb_get_attribute(dcb
, dev
, DCB_ATTR_IEEE_ETS
, ets
, sizeof(*ets
));
200 static int dcb_ets_validate_bw(const __u8 bw
[], const __u8 tsa
[], const char *what
)
202 bool has_ets
= false;
203 unsigned int total
= 0;
206 for (tc
= 0; tc
< IEEE_8021QAZ_MAX_TCS
; tc
++) {
207 if (tsa
[tc
] == IEEE_8021QAZ_TSA_ETS
) {
213 /* TC bandwidth is only intended for ETS, but 802.1Q-2018 only requires
214 * that the sum be 100, and individual entries 0..100. It explicitly
215 * notes that non-ETS TCs can have non-0 TC bandwidth during
218 for (tc
= 0; tc
< IEEE_8021QAZ_MAX_TCS
; tc
++) {
220 fprintf(stderr
, "%d%% for TC %d of %s is not a valid bandwidth percentage, expected 0..100%%\n",
227 /* This is what 802.1Q-2018 requires. */
231 /* But this requirement does not make sense for all-strict
232 * configurations. Anything else than 0 does not make sense: either BW
233 * has not been reconfigured for the all-strict allocation yet, at which
234 * point we expect sum of 100. Or it has already been reconfigured, at
235 * which point accept 0.
237 if (!has_ets
&& total
== 0)
240 fprintf(stderr
, "Bandwidth percentages in %s sum to %d%%, expected %d%%\n",
241 what
, total
, has_ets
? 100 : 0);
245 static int dcb_ets_set(struct dcb
*dcb
, const char *dev
, const struct ieee_ets
*ets
)
247 /* Do not validate pg-bw, which is not standard and has unclear
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"))
254 return dcb_set_attribute(dcb
, dev
, DCB_ATTR_IEEE_ETS
, ets
, sizeof(*ets
));
257 static int dcb_cmd_ets_set(struct dcb
*dcb
, const char *dev
, int argc
, char **argv
)
267 ret
= dcb_ets_get(dcb
, dev
, &ets
);
272 if (matches(*argv
, "help") == 0) {
275 } else if (matches(*argv
, "willing") == 0) {
277 ets
.willing
= parse_on_off("willing", *argv
, &ret
);
280 } else if (matches(*argv
, "tc-tsa") == 0) {
282 ret
= parse_mapping(&argc
, &argv
, true, &dcb_ets_parse_mapping_tc_tsa
,
285 fprintf(stderr
, "Invalid tc-tsa mapping %s\n", *argv
);
289 } else if (matches(*argv
, "reco-tc-tsa") == 0) {
291 ret
= parse_mapping(&argc
, &argv
, true, &dcb_ets_parse_mapping_tc_tsa
,
294 fprintf(stderr
, "Invalid reco-tc-tsa mapping %s\n", *argv
);
298 } else if (matches(*argv
, "tc-bw") == 0) {
300 ret
= parse_mapping(&argc
, &argv
, true, &dcb_ets_parse_mapping_tc_bw
,
303 fprintf(stderr
, "Invalid tc-bw mapping %s\n", *argv
);
307 } else if (matches(*argv
, "pg-bw") == 0) {
309 ret
= parse_mapping(&argc
, &argv
, true, &dcb_ets_parse_mapping_tc_bw
,
312 fprintf(stderr
, "Invalid pg-bw mapping %s\n", *argv
);
316 } else if (matches(*argv
, "reco-tc-bw") == 0) {
318 ret
= parse_mapping(&argc
, &argv
, true, &dcb_ets_parse_mapping_tc_bw
,
321 fprintf(stderr
, "Invalid reco-tc-bw mapping %s\n", *argv
);
325 } else if (matches(*argv
, "prio-tc") == 0) {
327 ret
= parse_mapping(&argc
, &argv
, true, &dcb_ets_parse_mapping_prio_tc
,
330 fprintf(stderr
, "Invalid prio-tc mapping %s\n", *argv
);
334 } else if (matches(*argv
, "reco-prio-tc") == 0) {
336 ret
= parse_mapping(&argc
, &argv
, true, &dcb_ets_parse_mapping_prio_tc
,
339 fprintf(stderr
, "Invalid reco-prio-tc mapping %s\n", *argv
);
344 fprintf(stderr
, "What is \"%s\"?\n", *argv
);
352 return dcb_ets_set(dcb
, dev
, &ets
);
355 static int dcb_cmd_ets_show(struct dcb
*dcb
, const char *dev
, int argc
, char **argv
)
360 ret
= dcb_ets_get(dcb
, dev
, &ets
);
364 open_json_object(NULL
);
372 if (matches(*argv
, "help") == 0) {
375 } else if (matches(*argv
, "willing") == 0) {
376 dcb_ets_print_willing(&ets
);
378 } else if (matches(*argv
, "ets-cap") == 0) {
379 dcb_ets_print_ets_cap(&ets
);
381 } else if (matches(*argv
, "cbs") == 0) {
382 dcb_ets_print_cbs(&ets
);
384 } else if (matches(*argv
, "tc-tsa") == 0) {
385 dcb_ets_print_tc_tsa(&ets
);
387 } else if (matches(*argv
, "reco-tc-tsa") == 0) {
388 dcb_ets_print_reco_tc_tsa(&ets
);
390 } else if (matches(*argv
, "tc-bw") == 0) {
391 dcb_ets_print_tc_bw(&ets
);
393 } else if (matches(*argv
, "pg-bw") == 0) {
394 dcb_ets_print_pg_bw(&ets
);
396 } else if (matches(*argv
, "reco-tc-bw") == 0) {
397 dcb_ets_print_reco_tc_bw(&ets
);
399 } else if (matches(*argv
, "prio-tc") == 0) {
400 dcb_ets_print_prio_tc(&ets
);
402 } else if (matches(*argv
, "reco-prio-tc") == 0) {
403 dcb_ets_print_reco_prio_tc(&ets
);
406 fprintf(stderr
, "What is \"%s\"?\n", *argv
);
419 int dcb_cmd_ets(struct dcb
*dcb
, int argc
, char **argv
)
421 if (!argc
|| matches(*argv
, "help") == 0) {
424 } else if (matches(*argv
, "show") == 0) {
426 return dcb_cmd_parse_dev(dcb
, argc
, argv
, dcb_cmd_ets_show
, dcb_ets_help_show
);
427 } else if (matches(*argv
, "set") == 0) {
429 return dcb_cmd_parse_dev(dcb
, argc
, argv
, dcb_cmd_ets_set
, dcb_ets_help_set
);
431 fprintf(stderr
, "What is \"%s\"?\n", *argv
);