From 7fe954ee34764eec65ed8b272b4b11c5a36f73a4 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 11 Dec 2020 00:02:15 +0100 Subject: [PATCH 01/10] dcb: Remove unsupported command line arguments from getopt_long() getopt_long() currently includes "c" and "n" in the short option string. These probably slipped in as a cut'n'paste, and are not actually accepted. Remove them. Signed-off-by: Petr Machata Signed-off-by: David Ahern --- dcb/dcb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dcb/dcb.c b/dcb/dcb.c index dc1e9fe0..217dd640 100644 --- a/dcb/dcb.c +++ b/dcb/dcb.c @@ -349,7 +349,7 @@ int main(int argc, char **argv) return EXIT_FAILURE; } - while ((opt = getopt_long(argc, argv, "b:c::fhjnpvN:V", + while ((opt = getopt_long(argc, argv, "b:fhjpvN:V", long_options, NULL)) >= 0) { switch (opt) { From 12d41d0184f70cbbc321efcb3668d1e1ff1da18e Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 11 Dec 2020 00:02:16 +0100 Subject: [PATCH 02/10] dcb: ets: Fix help display for "show" subcommand "dcb ets show dev X help" currently shows full "ets" help instead of just help for the show command. Fix it. Signed-off-by: Petr Machata Signed-off-by: David Ahern --- dcb/dcb_ets.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dcb/dcb_ets.c b/dcb/dcb_ets.c index 1735885a..94c6019e 100644 --- a/dcb/dcb_ets.c +++ b/dcb/dcb_ets.c @@ -370,7 +370,7 @@ static int dcb_cmd_ets_show(struct dcb *dcb, const char *dev, int argc, char **a do { if (matches(*argv, "help") == 0) { - dcb_ets_help(); + dcb_ets_help_show(); return 0; } else if (matches(*argv, "willing") == 0) { dcb_ets_print_willing(&ets); @@ -404,7 +404,7 @@ static int dcb_cmd_ets_show(struct dcb *dcb, const char *dev, int argc, char **a print_nl(); } else { fprintf(stderr, "What is \"%s\"?\n", *argv); - dcb_ets_help(); + dcb_ets_help_show(); return -EINVAL; } From a7c2eaac39a94e896d5b1c2e76aa4d0df3604527 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 11 Dec 2020 00:02:17 +0100 Subject: [PATCH 03/10] dcb: ets: Change the way show parameters are given in synopsis None, one, or many parameters can be given on the command line, but the current synopsis allows only none or one. Fix it. Signed-off-by: Petr Machata Signed-off-by: David Ahern --- dcb/dcb_ets.c | 6 +++--- man/man8/dcb-ets.8 | 13 ++++++++++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/dcb/dcb_ets.c b/dcb/dcb_ets.c index 94c6019e..c2088105 100644 --- a/dcb/dcb_ets.c +++ b/dcb/dcb_ets.c @@ -32,9 +32,9 @@ static void dcb_ets_help_show(void) { fprintf(stderr, "Usage: dcb ets show dev STRING\n" - " [ willing | ets-cap | cbs | tc-tsa | reco-tc-tsa |\n" - " pg-bw | tc-bw | reco-tc-bw | prio-tc |\n" - " reco-prio-tc ]\n" + " [ willing ] [ ets-cap ] [ cbs ] [ tc-tsa ]\n" + " [ reco-tc-tsa ] [ pg-bw ] [ tc-bw ] [ reco-tc-bw ]\n" + " [ prio-tc ] [ reco-prio-tc ]\n" "\n" ); } diff --git a/man/man8/dcb-ets.8 b/man/man8/dcb-ets.8 index 0ae3587c..1ef0948f 100644 --- a/man/man8/dcb-ets.8 +++ b/man/man8/dcb-ets.8 @@ -17,9 +17,16 @@ the DCB (Data Center Bridging) subsystem .ti -8 .B dcb ets show dev .RI DEV -.RB "[ { " willing " | " ets-cap " | " cbs " | " tc-tsa " | " reco-tc-tsa -.RB " | " pg-bw " | " tc-bw " | " reco-tc-bw " | " prio-tc -.RB " | " reco-prio-tc " } ]" +.RB "[ " willing " ]" +.RB "[ " ets-cap " ]" +.RB "[ " cbs " ]" +.RB "[ " tc-tsa " ]" +.RB "[ " reco-tc-tsa " ]" +.RB "[ " pg-bw " ]" +.RB "[ " tc-bw " ]" +.RB "[ " reco-tc-bw " ]" +.RB "[ " prio-tc " ]" +.RB "[ " reco-prio-tc " ]" .ti -8 .B dcb ets set dev From 7e94711c71cc40c0ab47c07de6b31bd788ead096 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 11 Dec 2020 00:02:18 +0100 Subject: [PATCH 04/10] man: dcb-ets: Remove an unnecessary empty line Signed-off-by: Petr Machata Signed-off-by: David Ahern --- man/man8/dcb-ets.8 | 1 - 1 file changed, 1 deletion(-) diff --git a/man/man8/dcb-ets.8 b/man/man8/dcb-ets.8 index 1ef0948f..9c64b33e 100644 --- a/man/man8/dcb-ets.8 +++ b/man/man8/dcb-ets.8 @@ -61,7 +61,6 @@ the DCB (Data Center Bridging) subsystem .ti -8 .IR PRIO " := { " \fB0\fR " .. " \fB7\fR " }" - .SH DESCRIPTION .B dcb ets From 11a72186a05710b290f1527f6f995b044a4fc501 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 11 Dec 2020 00:02:19 +0100 Subject: [PATCH 05/10] dcb: Add dcb_set_u32(), dcb_set_u64() The DCB buffer object has a settable array of 32-bit quantities, and the maxrate object of 64-bit ones. Adjust dcb_parse_mapping() and related helpers to support 64-bit values in mappings, and add appropriate helpers. Signed-off-by: Petr Machata Signed-off-by: David Ahern --- dcb/dcb.c | 22 ++++++++++++++++++---- dcb/dcb.h | 8 +++++--- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/dcb/dcb.c b/dcb/dcb.c index 217dd640..7c0beee4 100644 --- a/dcb/dcb.c +++ b/dcb/dcb.c @@ -229,8 +229,8 @@ void dcb_print_named_array(const char *json_name, const char *fp_name, } int dcb_parse_mapping(const char *what_key, __u32 key, __u32 max_key, - const char *what_value, __u32 value, __u32 max_value, - void (*set_array)(__u32 index, __u32 value, void *data), + const char *what_value, __u64 value, __u64 max_value, + void (*set_array)(__u32 index, __u64 value, void *data), void *set_array_data) { bool is_all = key == (__u32) -1; @@ -242,7 +242,7 @@ int dcb_parse_mapping(const char *what_key, __u32 key, __u32 max_key, } if (value > max_value) { - fprintf(stderr, "In %s:%s mapping, %s is expected to be 0..%d\n", + fprintf(stderr, "In %s:%s mapping, %s is expected to be 0..%llu\n", what_key, what_value, what_value, max_value); return -EINVAL; } @@ -257,13 +257,27 @@ int dcb_parse_mapping(const char *what_key, __u32 key, __u32 max_key, return 0; } -void dcb_set_u8(__u32 key, __u32 value, void *data) +void dcb_set_u8(__u32 key, __u64 value, void *data) { __u8 *array = data; array[key] = value; } +void dcb_set_u32(__u32 key, __u64 value, void *data) +{ + __u32 *array = data; + + array[key] = value; +} + +void dcb_set_u64(__u32 key, __u64 value, void *data) +{ + __u64 *array = data; + + array[key] = value; +} + int dcb_cmd_parse_dev(struct dcb *dcb, int argc, char **argv, int (*and_then)(struct dcb *dcb, const char *dev, int argc, char **argv), diff --git a/dcb/dcb.h b/dcb/dcb.h index 6f135ed0..d2217688 100644 --- a/dcb/dcb.h +++ b/dcb/dcb.h @@ -14,15 +14,17 @@ struct dcb { }; int dcb_parse_mapping(const char *what_key, __u32 key, __u32 max_key, - const char *what_value, __u32 value, __u32 max_value, - void (*set_array)(__u32 index, __u32 value, void *data), + const char *what_value, __u64 value, __u64 max_value, + void (*set_array)(__u32 index, __u64 value, void *data), void *set_array_data); int dcb_cmd_parse_dev(struct dcb *dcb, int argc, char **argv, int (*and_then)(struct dcb *dcb, const char *dev, int argc, char **argv), void (*help)(void)); -void dcb_set_u8(__u32 key, __u32 value, void *data); +void dcb_set_u8(__u32 key, __u64 value, void *data); +void dcb_set_u32(__u32 key, __u64 value, void *data); +void dcb_set_u64(__u32 key, __u64 value, void *data); int dcb_get_attribute(struct dcb *dcb, const char *dev, int attr, void *data, size_t data_len); From 6e9687db04518dc0856e622f232127ddab71132d Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 11 Dec 2020 00:02:20 +0100 Subject: [PATCH 06/10] dcb: Add -s to enable statistics Allow selective display of statistical counters by passing -s. Signed-off-by: Petr Machata Signed-off-by: David Ahern --- dcb/dcb.c | 9 +++++++-- dcb/dcb.h | 1 + man/man8/dcb.8 | 5 +++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/dcb/dcb.c b/dcb/dcb.c index 7c0beee4..9332a8b2 100644 --- a/dcb/dcb.c +++ b/dcb/dcb.c @@ -310,7 +310,8 @@ static void dcb_help(void) "Usage: dcb [ OPTIONS ] OBJECT { COMMAND | help }\n" " dcb [ -f | --force ] { -b | --batch } filename [ -N | --Netns ] netnsname\n" "where OBJECT := ets\n" - " OPTIONS := [ -V | --Version | -j | --json | -p | --pretty | -v | --verbose ]\n"); + " OPTIONS := [ -V | --Version | -j | --json | -p | --pretty\n" + " | -s | --statistics | -v | --verbose ]\n"); } static int dcb_cmd(struct dcb *dcb, int argc, char **argv) @@ -346,6 +347,7 @@ int main(int argc, char **argv) { "batch", required_argument, NULL, 'b' }, { "json", no_argument, NULL, 'j' }, { "pretty", no_argument, NULL, 'p' }, + { "statistics", no_argument, NULL, 's' }, { "Netns", required_argument, NULL, 'N' }, { "help", no_argument, NULL, 'h' }, { NULL, 0, NULL, 0 } @@ -363,7 +365,7 @@ int main(int argc, char **argv) return EXIT_FAILURE; } - while ((opt = getopt_long(argc, argv, "b:fhjpvN:V", + while ((opt = getopt_long(argc, argv, "b:fhjpsvN:V", long_options, NULL)) >= 0) { switch (opt) { @@ -383,6 +385,9 @@ int main(int argc, char **argv) case 'p': pretty = true; break; + case 's': + dcb->stats = true; + break; case 'N': if (netns_switch(optarg)) { ret = EXIT_FAILURE; diff --git a/dcb/dcb.h b/dcb/dcb.h index d2217688..b2a13b30 100644 --- a/dcb/dcb.h +++ b/dcb/dcb.h @@ -11,6 +11,7 @@ struct dcb { char *buf; struct mnl_socket *nl; bool json_output; + bool stats; }; int dcb_parse_mapping(const char *what_key, __u32 key, __u32 max_key, diff --git a/man/man8/dcb.8 b/man/man8/dcb.8 index f318435c..f853b7ba 100644 --- a/man/man8/dcb.8 +++ b/man/man8/dcb.8 @@ -51,6 +51,11 @@ Generate JSON output. .BR "\-p" , " --pretty" When combined with -j generate a pretty JSON output. +.TP +.BR "\-s" , " --statistics" +If the object in question contains any statistical counters, shown them as +part of the "show" output. + .SH OBJECTS .TP From 808dd741fce1158e824ae5bdf367947ae764be19 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 11 Dec 2020 00:02:21 +0100 Subject: [PATCH 07/10] dcb: Add -i to enable IEC mode Allow switching "dcb" into the ISO/IEC mode of units by passing -i. Signed-off-by: Petr Machata Signed-off-by: David Ahern --- dcb/dcb.c | 10 +++++++--- dcb/dcb.h | 1 + man/man8/dcb.8 | 5 +++++ 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/dcb/dcb.c b/dcb/dcb.c index 9332a8b2..4b4a5b93 100644 --- a/dcb/dcb.c +++ b/dcb/dcb.c @@ -310,8 +310,8 @@ static void dcb_help(void) "Usage: dcb [ OPTIONS ] OBJECT { COMMAND | help }\n" " dcb [ -f | --force ] { -b | --batch } filename [ -N | --Netns ] netnsname\n" "where OBJECT := ets\n" - " OPTIONS := [ -V | --Version | -j | --json | -p | --pretty\n" - " | -s | --statistics | -v | --verbose ]\n"); + " OPTIONS := [ -V | --Version | -i | --iec | -j | --json\n" + " | -p | --pretty | -s | --statistics | -v | --verbose]\n"); } static int dcb_cmd(struct dcb *dcb, int argc, char **argv) @@ -345,6 +345,7 @@ int main(int argc, char **argv) { "Version", no_argument, NULL, 'V' }, { "force", no_argument, NULL, 'f' }, { "batch", required_argument, NULL, 'b' }, + { "iec", no_argument, NULL, 'i' }, { "json", no_argument, NULL, 'j' }, { "pretty", no_argument, NULL, 'p' }, { "statistics", no_argument, NULL, 's' }, @@ -365,7 +366,7 @@ int main(int argc, char **argv) return EXIT_FAILURE; } - while ((opt = getopt_long(argc, argv, "b:fhjpsvN:V", + while ((opt = getopt_long(argc, argv, "b:fhijpsvN:V", long_options, NULL)) >= 0) { switch (opt) { @@ -394,6 +395,9 @@ int main(int argc, char **argv) goto dcb_free; } break; + case 'i': + dcb->use_iec = true; + break; case 'h': dcb_help(); return 0; diff --git a/dcb/dcb.h b/dcb/dcb.h index b2a13b30..8637efc1 100644 --- a/dcb/dcb.h +++ b/dcb/dcb.h @@ -12,6 +12,7 @@ struct dcb { struct mnl_socket *nl; bool json_output; bool stats; + bool use_iec; }; int dcb_parse_mapping(const char *what_key, __u32 key, __u32 max_key, diff --git a/man/man8/dcb.8 b/man/man8/dcb.8 index f853b7ba..15b43942 100644 --- a/man/man8/dcb.8 +++ b/man/man8/dcb.8 @@ -43,6 +43,11 @@ failure will cause termination of dcb. Don't terminate dcb on errors in batch mode. If there were any errors during execution of the commands, the application return code will be non zero. +.TP +.BR "\-i" , " --iec" +When showing rates, use ISO/IEC 1024-based prefixes (Ki, Mi, Bi) instead of +the 1000-based ones (K, M, B). + .TP .BR "\-j" , " --json" Generate JSON output. From 6567cb588b15883d7b0bdc9fcc9d2a7a8f37fa3e Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 11 Dec 2020 00:02:22 +0100 Subject: [PATCH 08/10] dcb: Add a subtool for the DCB PFC object PFC, for "Priority-based Flow Control", allows configuration of priority lossiness, and related toggles. Add a dcb subtool to allow showing and tweaking of individual PFC configuration options, and querying statistics. For example: # dcb pfc show dev eni1np1 pfc-cap 8 macsec-bypass on delay 0 pg-pfc 0:off 1:on 2:off 3:off 4:off 5:off 6:off 7:on requests 0:0 1:217 2:0 3:0 4:0 5:0 6:0 7:28 indications 0:0 1:179 2:0 3:0 4:0 5:0 6:0 7:18 Signed-off-by: Petr Machata Signed-off-by: David Ahern --- dcb/Makefile | 2 +- dcb/dcb.c | 27 ++++- dcb/dcb.h | 6 + dcb/dcb_pfc.c | 286 +++++++++++++++++++++++++++++++++++++++++++++ man/man8/dcb-pfc.8 | 127 ++++++++++++++++++++ man/man8/dcb.8 | 9 +- 6 files changed, 453 insertions(+), 4 deletions(-) create mode 100644 dcb/dcb_pfc.c create mode 100644 man/man8/dcb-pfc.8 diff --git a/dcb/Makefile b/dcb/Makefile index 89581716..ea557a30 100644 --- a/dcb/Makefile +++ b/dcb/Makefile @@ -5,7 +5,7 @@ TARGETS := ifeq ($(HAVE_MNL),y) -DCBOBJ = dcb.o dcb_ets.o +DCBOBJ = dcb.o dcb_ets.o dcb_pfc.o TARGETS += dcb endif diff --git a/dcb/dcb.c b/dcb/dcb.c index 4b4a5b93..cc07d3dd 100644 --- a/dcb/dcb.c +++ b/dcb/dcb.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ +#include #include #include #include @@ -201,6 +202,28 @@ void dcb_print_array_u8(const __u8 *array, size_t size) } } +void dcb_print_array_u64(const __u64 *array, size_t size) +{ + SPRINT_BUF(b); + size_t i; + + for (i = 0; i < size; i++) { + snprintf(b, sizeof(b), "%zd:%%" PRIu64 " ", i); + print_u64(PRINT_ANY, NULL, b, array[i]); + } +} + +void dcb_print_array_on_off(const __u8 *array, size_t size) +{ + SPRINT_BUF(b); + size_t i; + + for (i = 0; i < size; i++) { + snprintf(b, sizeof(b), "%zd:%%s ", i); + print_on_off(PRINT_ANY, NULL, b, array[i]); + } +} + void dcb_print_array_kw(const __u8 *array, size_t array_size, const char *const kw[], size_t kw_size) { @@ -309,7 +332,7 @@ static void dcb_help(void) fprintf(stderr, "Usage: dcb [ OPTIONS ] OBJECT { COMMAND | help }\n" " dcb [ -f | --force ] { -b | --batch } filename [ -N | --Netns ] netnsname\n" - "where OBJECT := ets\n" + "where OBJECT := { ets | pfc }\n" " OPTIONS := [ -V | --Version | -i | --iec | -j | --json\n" " | -p | --pretty | -s | --statistics | -v | --verbose]\n"); } @@ -321,6 +344,8 @@ static int dcb_cmd(struct dcb *dcb, int argc, char **argv) return 0; } else if (matches(*argv, "ets") == 0) { return dcb_cmd_ets(dcb, argc - 1, argv + 1); + } else if (matches(*argv, "pfc") == 0) { + return dcb_cmd_pfc(dcb, argc - 1, argv + 1); } fprintf(stderr, "Object \"%s\" is unknown\n", *argv); diff --git a/dcb/dcb.h b/dcb/dcb.h index 8637efc1..4ecc6afd 100644 --- a/dcb/dcb.h +++ b/dcb/dcb.h @@ -37,6 +37,8 @@ void dcb_print_named_array(const char *json_name, const char *fp_name, const __u8 *array, size_t size, void (*print_array)(const __u8 *, size_t)); void dcb_print_array_u8(const __u8 *array, size_t size); +void dcb_print_array_u64(const __u64 *array, size_t size); +void dcb_print_array_on_off(const __u8 *array, size_t size); void dcb_print_array_kw(const __u8 *array, size_t array_size, const char *const kw[], size_t kw_size); @@ -44,4 +46,8 @@ void dcb_print_array_kw(const __u8 *array, size_t array_size, int dcb_cmd_ets(struct dcb *dcb, int argc, char **argv); +/* dcb_pfc.c */ + +int dcb_cmd_pfc(struct dcb *dcb, int argc, char **argv); + #endif /* __DCB_H__ */ diff --git a/dcb/dcb_pfc.c b/dcb/dcb_pfc.c new file mode 100644 index 00000000..aaa09022 --- /dev/null +++ b/dcb/dcb_pfc.c @@ -0,0 +1,286 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include +#include +#include + +#include "dcb.h" +#include "utils.h" + +static void dcb_pfc_help_set(void) +{ + fprintf(stderr, + "Usage: dcb pfc set dev STRING\n" + " [ prio-pfc PFC-MAP ]\n" + " [ macsec-bypass { on | off } ]\n" + " [ delay INTEGER ]\n" + "\n" + " where PFC-MAP := [ PFC-MAP ] PFC-MAPPING\n" + " PFC-MAPPING := { all | TC }:PFC\n" + " TC := { 0 .. 7 }\n" + " PFC := { on | off }\n" + "\n" + ); +} + +static void dcb_pfc_help_show(void) +{ + fprintf(stderr, + "Usage: dcb [ -s ] pfc show dev STRING\n" + " [ pfc-cap ] [ prio-pfc ] [ macsec-bypass ]\n" + " [ delay ] [ requests ] [ indications ]\n" + "\n" + ); +} + +static void dcb_pfc_help(void) +{ + fprintf(stderr, + "Usage: dcb pfc help\n" + "\n" + ); + dcb_pfc_help_show(); + dcb_pfc_help_set(); +} + +static void dcb_pfc_to_array(__u8 array[IEEE_8021QAZ_MAX_TCS], __u8 pfc_en) +{ + int i; + + for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) + array[i] = !!(pfc_en & (1 << i)); +} + +static void dcb_pfc_from_array(__u8 array[IEEE_8021QAZ_MAX_TCS], __u8 *pfc_en_p) +{ + __u8 pfc_en = 0; + int i; + + for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { + if (array[i]) + pfc_en |= 1 << i; + } + + *pfc_en_p = pfc_en; +} + +static int dcb_pfc_parse_mapping_prio_pfc(__u32 key, char *value, void *data) +{ + struct ieee_pfc *pfc = data; + __u8 pfc_en[IEEE_8021QAZ_MAX_TCS]; + bool enabled; + int ret; + + dcb_pfc_to_array(pfc_en, pfc->pfc_en); + + enabled = parse_on_off("PFC", value, &ret); + if (ret) + return ret; + + ret = dcb_parse_mapping("PRIO", key, IEEE_8021QAZ_MAX_TCS - 1, + "PFC", enabled, -1, + dcb_set_u8, pfc_en); + if (ret) + return ret; + + dcb_pfc_from_array(pfc_en, &pfc->pfc_en); + return 0; +} + +static void dcb_pfc_print_pfc_cap(const struct ieee_pfc *pfc) +{ + print_uint(PRINT_ANY, "pfc_cap", "pfc-cap %d ", pfc->pfc_cap); +} + +static void dcb_pfc_print_macsec_bypass(const struct ieee_pfc *pfc) +{ + print_on_off(PRINT_ANY, "macsec_bypass", "macsec-bypass %s ", pfc->mbc); +} + +static void dcb_pfc_print_delay(const struct ieee_pfc *pfc) +{ + print_uint(PRINT_ANY, "delay", "delay %d ", pfc->delay); +} + +static void dcb_pfc_print_prio_pfc(const struct ieee_pfc *pfc) +{ + __u8 pfc_en[IEEE_8021QAZ_MAX_TCS]; + + dcb_pfc_to_array(pfc_en, pfc->pfc_en); + dcb_print_named_array("prio_pfc", "prio-pfc", + pfc_en, ARRAY_SIZE(pfc_en), &dcb_print_array_on_off); +} + +static void dcb_pfc_print_requests(const struct ieee_pfc *pfc) +{ + open_json_array(PRINT_JSON, "requests"); + print_string(PRINT_FP, NULL, "requests ", NULL); + dcb_print_array_u64(pfc->requests, ARRAY_SIZE(pfc->requests)); + close_json_array(PRINT_JSON, "requests"); +} + +static void dcb_pfc_print_indications(const struct ieee_pfc *pfc) +{ + open_json_array(PRINT_JSON, "indications"); + print_string(PRINT_FP, NULL, "indications ", NULL); + dcb_print_array_u64(pfc->indications, ARRAY_SIZE(pfc->indications)); + close_json_array(PRINT_JSON, "indications"); +} + +static void dcb_pfc_print(const struct dcb *dcb, const struct ieee_pfc *pfc) +{ + dcb_pfc_print_pfc_cap(pfc); + dcb_pfc_print_macsec_bypass(pfc); + dcb_pfc_print_delay(pfc); + print_nl(); + + dcb_pfc_print_prio_pfc(pfc); + print_nl(); + + if (dcb->stats) { + dcb_pfc_print_requests(pfc); + print_nl(); + + dcb_pfc_print_indications(pfc); + print_nl(); + } +} + +static int dcb_pfc_get(struct dcb *dcb, const char *dev, struct ieee_pfc *pfc) +{ + return dcb_get_attribute(dcb, dev, DCB_ATTR_IEEE_PFC, pfc, sizeof(*pfc)); +} + +static int dcb_pfc_set(struct dcb *dcb, const char *dev, const struct ieee_pfc *pfc) +{ + return dcb_set_attribute(dcb, dev, DCB_ATTR_IEEE_PFC, pfc, sizeof(*pfc)); +} + +static int dcb_cmd_pfc_set(struct dcb *dcb, const char *dev, int argc, char **argv) +{ + struct ieee_pfc pfc; + int ret; + + if (!argc) { + dcb_pfc_help_set(); + return 0; + } + + ret = dcb_pfc_get(dcb, dev, &pfc); + if (ret) + return ret; + + do { + if (matches(*argv, "help") == 0) { + dcb_pfc_help_set(); + return 0; + } else if (matches(*argv, "prio-pfc") == 0) { + NEXT_ARG(); + ret = parse_mapping(&argc, &argv, true, + &dcb_pfc_parse_mapping_prio_pfc, &pfc); + if (ret) { + fprintf(stderr, "Invalid pfc mapping %s\n", *argv); + return ret; + } + continue; + } else if (matches(*argv, "macsec-bypass") == 0) { + NEXT_ARG(); + pfc.mbc = parse_on_off("macsec-bypass", *argv, &ret); + if (ret) + return ret; + } else if (matches(*argv, "delay") == 0) { + NEXT_ARG(); + /* Do not support the size notations for delay. + * Delay is specified in "bit times", not bits, so + * it is not applicable. At the same time it would + * be confusing that 10Kbit does not mean 10240, + * but 1280. + */ + if (get_u16(&pfc.delay, *argv, 0)) { + fprintf(stderr, "Invalid delay `%s', expected an integer 0..65535\n", + *argv); + return -EINVAL; + } + } else { + fprintf(stderr, "What is \"%s\"?\n", *argv); + dcb_pfc_help_set(); + return -EINVAL; + } + + NEXT_ARG_FWD(); + } while (argc > 0); + + return dcb_pfc_set(dcb, dev, &pfc); +} + +static int dcb_cmd_pfc_show(struct dcb *dcb, const char *dev, int argc, char **argv) +{ + struct ieee_pfc pfc; + int ret; + + ret = dcb_pfc_get(dcb, dev, &pfc); + if (ret) + return ret; + + open_json_object(NULL); + + if (!argc) { + dcb_pfc_print(dcb, &pfc); + goto out; + } + + do { + if (matches(*argv, "help") == 0) { + dcb_pfc_help_show(); + return 0; + } else if (matches(*argv, "prio-pfc") == 0) { + dcb_pfc_print_prio_pfc(&pfc); + print_nl(); + } else if (matches(*argv, "pfc-cap") == 0) { + dcb_pfc_print_pfc_cap(&pfc); + print_nl(); + } else if (matches(*argv, "macsec-bypass") == 0) { + dcb_pfc_print_macsec_bypass(&pfc); + print_nl(); + } else if (matches(*argv, "delay") == 0) { + dcb_pfc_print_delay(&pfc); + print_nl(); + } else if (matches(*argv, "requests") == 0) { + dcb_pfc_print_requests(&pfc); + print_nl(); + } else if (matches(*argv, "indications") == 0) { + dcb_pfc_print_indications(&pfc); + print_nl(); + } else { + fprintf(stderr, "What is \"%s\"?\n", *argv); + dcb_pfc_help_show(); + return -EINVAL; + } + + NEXT_ARG_FWD(); + } while (argc > 0); + +out: + close_json_object(); + return 0; +} + +int dcb_cmd_pfc(struct dcb *dcb, int argc, char **argv) +{ + if (!argc || matches(*argv, "help") == 0) { + dcb_pfc_help(); + return 0; + } else if (matches(*argv, "show") == 0) { + NEXT_ARG_FWD(); + return dcb_cmd_parse_dev(dcb, argc, argv, + dcb_cmd_pfc_show, dcb_pfc_help_show); + } else if (matches(*argv, "set") == 0) { + NEXT_ARG_FWD(); + return dcb_cmd_parse_dev(dcb, argc, argv, + dcb_cmd_pfc_set, dcb_pfc_help_set); + } else { + fprintf(stderr, "What is \"%s\"?\n", *argv); + dcb_pfc_help(); + return -EINVAL; + } +} diff --git a/man/man8/dcb-pfc.8 b/man/man8/dcb-pfc.8 new file mode 100644 index 00000000..735c16e0 --- /dev/null +++ b/man/man8/dcb-pfc.8 @@ -0,0 +1,127 @@ +.TH DCB-PFC 8 "31 October 2020" "iproute2" "Linux" +.SH NAME +dcb-pfc \- show / manipulate PFC (Priority-based Flow Control) settings of +the DCB (Data Center Bridging) subsystem +.SH SYNOPSIS +.sp +.ad l +.in +8 + +.ti -8 +.B dcb +.RI "[ " OPTIONS " ] " +.B pfc +.RI "{ " COMMAND " | " help " }" +.sp + +.ti -8 +.B dcb pfc show dev +.RI DEV +.RB "[ " pfc-cap " ]" +.RB "[ " prio-pfc " ]" +.RB "[ " macsec-bypass " ]" +.RB "[ " delay " ]" +.RB "[ " requests " ]" +.RB "[ " indications " ]" + +.ti -8 +.B dcb pfc set dev +.RI DEV +.RB "[ " prio-pfc " " \fIPFC-MAP " ]" +.RB "[ " macsec-bypass " { " on " | " off " } ]" +.RB "[ " delay " " \fIINTEGER\fR " ]" + +.ti -8 +.IR PFC-MAP " := [ " PFC-MAP " ] " PFC-MAPPING + +.ti -8 +.IR PFC-MAPPING " := { " PRIO " | " \fBall " }" \fB:\fR "{ " +.IR \fBon\fR " | " \fBoff\fR " }" + +.ti -8 +.IR PRIO " := { " \fB0\fR " .. " \fB7\fR " }" + +.SH DESCRIPTION + +.B dcb pfc +is used to configure Priority-based Flow Control attributes through Linux +DCB (Data Center Bridging) interface. PFC permits marking flows with a +certain priority as lossless, and holds related configuration, as well as +PFC counters. + +.SH PARAMETERS + +For read-write parameters, the following describes only the write direction, +i.e. as used with the \fBset\fR command. For the \fBshow\fR command, the +parameter name is to be used as a simple keyword without further arguments. This +instructs the tool to show the value of a given parameter. When no parameters +are given, the tool shows the complete PFC configuration. + +.TP +.B pfc-cap +A read-only property that shows the number of traffic classes that may +simultaneously support PFC. + +.TP +.B requests +A read-only count of the sent PFC frames per traffic class. Only shown when +-s is given, or when requested explicitly. + +.TP +.B indications +A read-only count of the received PFC frames per traffic class. Only shown +when -s is given, or when requested explicitly. + +.TP +.B macsec-bypass \fR{ \fBon\fR | \fBoff\fR } +Whether the sending station is capable of bypassing MACsec processing when +MACsec is disabled. + +.TP +.B prio-pfc \fIPFC-MAP +\fIPFC-MAP\fR uses the array parameter syntax, see +.BR dcb (8) +for details. Keys are priorities, values are on / off indicators of whether +PFC is enabled for a given priority. + +.TP +.B delay \fIINTEGER +The allowance made for round-trip propagation delay of the link in bits. +The value shall be 0..65535. + +.SH EXAMPLE & USAGE + +Enable PFC on priorities 6 and 7, leaving the rest intact: + +.P +# dcb pfc set dev eth0 prio-pfc 6:on 7:on + +Disable PFC of all priorities except 6 and 7, and configure delay to 4096 +bits: + +.P +# dcb pfc set dev eth0 prio-pfc all:off 6:on 7:on delay 0x1000 + +Show what was set: + +.P +# dcb pfc show dev eth0 +.br +pfc-cap 8 macsec-bypass off delay 4096 +.br +prio-pfc 0:off 1:off 2:off 3:off 4:off 5:off 6:on 7:on + +.SH EXIT STATUS +Exit status is 0 if command was successful or a positive integer upon failure. + +.SH SEE ALSO +.BR dcb (8) + +.SH REPORTING BUGS +Report any bugs to the Network Developers mailing list +.B +where the development and maintenance is primarily done. +You do not have to be subscribed to the list to send a message there. + +.SH AUTHOR +Petr Machata diff --git a/man/man8/dcb.8 b/man/man8/dcb.8 index 15b43942..01febe16 100644 --- a/man/man8/dcb.8 +++ b/man/man8/dcb.8 @@ -9,7 +9,7 @@ dcb \- show / manipulate DCB (Data Center Bridging) settings .ti -8 .B dcb .RI "[ " OPTIONS " ] " -.B ets +.RB "{ " ets " | " pfc " }" .RI "{ " COMMAND " | " help " }" .sp @@ -67,6 +67,10 @@ part of the "show" output. .B ets - Configuration of ETS (Enhanced Transmission Selection) +.TP +.B pfc +- Configuration of PFC (Priority-based Flow Control) + .SH COMMANDS A \fICOMMAND\fR specifies the action to perform on the object. The set of @@ -111,7 +115,8 @@ other values: Exit status is 0 if command was successful or a positive integer upon failure. .SH SEE ALSO -.BR dcb-ets (8) +.BR dcb-ets (8), +.BR dcb-pfc (8) .br .SH REPORTING BUGS From 2e36f91000e4b75f58daba08d4387b666159ac61 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 11 Dec 2020 00:02:23 +0100 Subject: [PATCH 09/10] dcb: Add a subtool for the DCB buffer object DCBNL buffer interfaces are an extension to the 802.1q DCB interfaces and allow configuration of port headroom buffers. Add a dcb subtool to allow showing and tweaking of buffer priority mapping and buffer sizes. For example: # dcb buf show dev eni1np1 prio-buffer 0:0 1:0 2:0 3:3 4:0 5:0 6:6 7:0 buffer-size 0:10000 1:0 2:0 3:70000 4:0 5:0 6:10000 7:0 total-size 221072 Signed-off-by: Petr Machata Signed-off-by: David Ahern --- dcb/Makefile | 2 +- dcb/dcb.c | 4 +- dcb/dcb.h | 4 + dcb/dcb_buffer.c | 235 ++++++++++++++++++++++++++++++++++++++++++ man/man8/dcb-buffer.8 | 126 ++++++++++++++++++++++ man/man8/dcb.8 | 7 +- 6 files changed, 375 insertions(+), 3 deletions(-) create mode 100644 dcb/dcb_buffer.c create mode 100644 man/man8/dcb-buffer.8 diff --git a/dcb/Makefile b/dcb/Makefile index ea557a30..dc84422f 100644 --- a/dcb/Makefile +++ b/dcb/Makefile @@ -5,7 +5,7 @@ TARGETS := ifeq ($(HAVE_MNL),y) -DCBOBJ = dcb.o dcb_ets.o dcb_pfc.o +DCBOBJ = dcb.o dcb_buffer.o dcb_ets.o dcb_pfc.o TARGETS += dcb endif diff --git a/dcb/dcb.c b/dcb/dcb.c index cc07d3dd..570405a7 100644 --- a/dcb/dcb.c +++ b/dcb/dcb.c @@ -332,7 +332,7 @@ static void dcb_help(void) fprintf(stderr, "Usage: dcb [ OPTIONS ] OBJECT { COMMAND | help }\n" " dcb [ -f | --force ] { -b | --batch } filename [ -N | --Netns ] netnsname\n" - "where OBJECT := { ets | pfc }\n" + "where OBJECT := { buffer | ets | pfc }\n" " OPTIONS := [ -V | --Version | -i | --iec | -j | --json\n" " | -p | --pretty | -s | --statistics | -v | --verbose]\n"); } @@ -342,6 +342,8 @@ static int dcb_cmd(struct dcb *dcb, int argc, char **argv) if (!argc || matches(*argv, "help") == 0) { dcb_help(); return 0; + } else if (matches(*argv, "buffer") == 0) { + return dcb_cmd_buffer(dcb, argc - 1, argv + 1); } else if (matches(*argv, "ets") == 0) { return dcb_cmd_ets(dcb, argc - 1, argv + 1); } else if (matches(*argv, "pfc") == 0) { diff --git a/dcb/dcb.h b/dcb/dcb.h index 4ecc6afd..0638d639 100644 --- a/dcb/dcb.h +++ b/dcb/dcb.h @@ -42,6 +42,10 @@ void dcb_print_array_on_off(const __u8 *array, size_t size); void dcb_print_array_kw(const __u8 *array, size_t array_size, const char *const kw[], size_t kw_size); +/* dcb_buffer.c */ + +int dcb_cmd_buffer(struct dcb *dcb, int argc, char **argv); + /* dcb_ets.c */ int dcb_cmd_ets(struct dcb *dcb, int argc, char **argv); diff --git a/dcb/dcb_buffer.c b/dcb/dcb_buffer.c new file mode 100644 index 00000000..e6a88a00 --- /dev/null +++ b/dcb/dcb_buffer.c @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include +#include +#include +#include + +#include "dcb.h" +#include "utils.h" + +static void dcb_buffer_help_set(void) +{ + fprintf(stderr, + "Usage: dcb buffer set dev STRING\n" + " [ prio-buffer PRIO-MAP ]\n" + " [ buffer-size SIZE-MAP ]\n" + "\n" + " where PRIO-MAP := [ PRIO-MAP ] PRIO-MAPPING\n" + " PRIO-MAPPING := { all | PRIO }:BUFFER\n" + " SIZE-MAP := [ SIZE-MAP ] SIZE-MAPPING\n" + " SIZE-MAPPING := { all | BUFFER }:INTEGER\n" + " PRIO := { 0 .. 7 }\n" + " BUFFER := { 0 .. 7 }\n" + "\n" + ); +} + +static void dcb_buffer_help_show(void) +{ + fprintf(stderr, + "Usage: dcb buffer show dev STRING\n" + " [ prio-buffer ] [ buffer-size ] [ total-size ]\n" + "\n" + ); +} + +static void dcb_buffer_help(void) +{ + fprintf(stderr, + "Usage: dcb buffer help\n" + "\n" + ); + dcb_buffer_help_show(); + dcb_buffer_help_set(); +} + +static int dcb_buffer_parse_mapping_prio_buffer(__u32 key, char *value, void *data) +{ + struct dcbnl_buffer *buffer = data; + __u8 buf; + + if (get_u8(&buf, value, 0)) + return -EINVAL; + + return dcb_parse_mapping("PRIO", key, IEEE_8021Q_MAX_PRIORITIES - 1, + "BUFFER", buf, DCBX_MAX_BUFFERS - 1, + dcb_set_u8, buffer->prio2buffer); +} + +static int dcb_buffer_parse_mapping_buffer_size(__u32 key, char *value, void *data) +{ + struct dcbnl_buffer *buffer = data; + unsigned int size; + + if (get_size(&size, value)) { + fprintf(stderr, "%d:%s: Illegal value for buffer size\n", key, value); + return -EINVAL; + } + + return dcb_parse_mapping("BUFFER", key, DCBX_MAX_BUFFERS - 1, + "INTEGER", size, -1, + dcb_set_u32, buffer->buffer_size); +} + +static void dcb_buffer_print_total_size(const struct dcbnl_buffer *buffer) +{ + print_size(PRINT_ANY, "total_size", "total-size %s ", buffer->total_size); +} + +static void dcb_buffer_print_prio_buffer(const struct dcbnl_buffer *buffer) +{ + dcb_print_named_array("prio_buffer", "prio-buffer", + buffer->prio2buffer, ARRAY_SIZE(buffer->prio2buffer), + dcb_print_array_u8); +} + +static void dcb_buffer_print_buffer_size(const struct dcbnl_buffer *buffer) +{ + size_t size = ARRAY_SIZE(buffer->buffer_size); + SPRINT_BUF(b); + size_t i; + + open_json_array(PRINT_JSON, "buffer_size"); + print_string(PRINT_FP, NULL, "buffer-size ", NULL); + + for (i = 0; i < size; i++) { + snprintf(b, sizeof(b), "%zd:%%s ", i); + print_size(PRINT_ANY, NULL, b, buffer->buffer_size[i]); + } + + close_json_array(PRINT_JSON, "buffer_size"); +} + +static void dcb_buffer_print(const struct dcbnl_buffer *buffer) +{ + dcb_buffer_print_prio_buffer(buffer); + print_nl(); + + dcb_buffer_print_buffer_size(buffer); + print_nl(); + + dcb_buffer_print_total_size(buffer); + print_nl(); +} + +static int dcb_buffer_get(struct dcb *dcb, const char *dev, struct dcbnl_buffer *buffer) +{ + return dcb_get_attribute(dcb, dev, DCB_ATTR_DCB_BUFFER, buffer, sizeof(*buffer)); +} + +static int dcb_buffer_set(struct dcb *dcb, const char *dev, const struct dcbnl_buffer *buffer) +{ + return dcb_set_attribute(dcb, dev, DCB_ATTR_DCB_BUFFER, buffer, sizeof(*buffer)); +} + +static int dcb_cmd_buffer_set(struct dcb *dcb, const char *dev, int argc, char **argv) +{ + struct dcbnl_buffer buffer; + int ret; + + if (!argc) { + dcb_buffer_help_set(); + return 0; + } + + ret = dcb_buffer_get(dcb, dev, &buffer); + if (ret) + return ret; + + do { + if (matches(*argv, "help") == 0) { + dcb_buffer_help_set(); + return 0; + } else if (matches(*argv, "prio-buffer") == 0) { + NEXT_ARG(); + ret = parse_mapping(&argc, &argv, true, + &dcb_buffer_parse_mapping_prio_buffer, &buffer); + if (ret) { + fprintf(stderr, "Invalid priority mapping %s\n", *argv); + return ret; + } + continue; + } else if (matches(*argv, "buffer-size") == 0) { + NEXT_ARG(); + ret = parse_mapping(&argc, &argv, true, + &dcb_buffer_parse_mapping_buffer_size, &buffer); + if (ret) { + fprintf(stderr, "Invalid buffer size mapping %s\n", *argv); + return ret; + } + continue; + } else { + fprintf(stderr, "What is \"%s\"?\n", *argv); + dcb_buffer_help_set(); + return -EINVAL; + } + + NEXT_ARG_FWD(); + } while (argc > 0); + + return dcb_buffer_set(dcb, dev, &buffer); +} + +static int dcb_cmd_buffer_show(struct dcb *dcb, const char *dev, int argc, char **argv) +{ + struct dcbnl_buffer buffer; + int ret; + + ret = dcb_buffer_get(dcb, dev, &buffer); + if (ret) + return ret; + + open_json_object(NULL); + + if (!argc) { + dcb_buffer_print(&buffer); + goto out; + } + + do { + if (matches(*argv, "help") == 0) { + dcb_buffer_help_show(); + return 0; + } else if (matches(*argv, "prio-buffer") == 0) { + dcb_buffer_print_prio_buffer(&buffer); + print_nl(); + } else if (matches(*argv, "buffer-size") == 0) { + dcb_buffer_print_buffer_size(&buffer); + print_nl(); + } else if (matches(*argv, "total-size") == 0) { + dcb_buffer_print_total_size(&buffer); + print_nl(); + } else { + fprintf(stderr, "What is \"%s\"?\n", *argv); + dcb_buffer_help_show(); + return -EINVAL; + } + + NEXT_ARG_FWD(); + } while (argc > 0); + +out: + close_json_object(); + return 0; +} + +int dcb_cmd_buffer(struct dcb *dcb, int argc, char **argv) +{ + if (!argc || matches(*argv, "help") == 0) { + dcb_buffer_help(); + return 0; + } else if (matches(*argv, "show") == 0) { + NEXT_ARG_FWD(); + return dcb_cmd_parse_dev(dcb, argc, argv, + dcb_cmd_buffer_show, dcb_buffer_help_show); + } else if (matches(*argv, "set") == 0) { + NEXT_ARG_FWD(); + return dcb_cmd_parse_dev(dcb, argc, argv, + dcb_cmd_buffer_set, dcb_buffer_help_set); + } else { + fprintf(stderr, "What is \"%s\"?\n", *argv); + dcb_buffer_help(); + return -EINVAL; + } +} diff --git a/man/man8/dcb-buffer.8 b/man/man8/dcb-buffer.8 new file mode 100644 index 00000000..c7ba6a99 --- /dev/null +++ b/man/man8/dcb-buffer.8 @@ -0,0 +1,126 @@ +.TH DCB-BUFFER 8 "12 November 2020" "iproute2" "Linux" +.SH NAME +dcb-buffer \- show / manipulate port buffer settings of +the DCB (Data Center Bridging) subsystem +.SH SYNOPSIS +.sp +.ad l +.in +8 + +.ti -8 +.B dcb +.RI "[ " OPTIONS " ] " +.B buffer +.RI "{ " COMMAND " | " help " }" +.sp + +.ti -8 +.B dcb buffer show dev +.RI DEV +.RB "[ " prio-buffer " ]" +.RB "[ " buffer-size " ]" +.RB "[ " total-size " ]" + +.ti -8 +.B dcb buffer set dev +.RI DEV +.RB "[ " prio-buffer " " \fIPRIO-MAP " ]" +.RB "[ " buffer-size " " \fISIZE-MAP " ]" + +.ti -8 +.IR PRIO-MAP " := [ " PRIO-MAP " ] " PRIO-MAPPING + +.ti -8 +.IR PRIO-MAPPING " := { " PRIO " | " \fBall " }" \fB:\fIBUFFER\fR + +.ti -8 +.IR SIZE-MAP " := [ " SIZE-MAP " ] " SIZE-MAPPING + +.ti -8 +.IR SIZE-MAPPING " := { " BUFFER " | " \fBall " }" \fB:\fISIZE\fR + +.ti -8 +.IR PRIO " := { " \fB0\fR " .. " \fB7\fR " }" + +.ti -8 +.IR BUFFER " := { " \fB0\fR " .. " \fB7\fR " }" + +.ti -8 +.IR SIZE " := { " INTEGER " | " INTEGER\fBK\fR " | " INTEGER\fBM\fR " | " ... " }" + +.SH DESCRIPTION + +.B dcb buffer +is used to configure assignment of traffic to port buffers based on traffic +priority, and sizes of those buffers. It can be also used to inspect the current +configuration, as well as total device memory that the port buffers take. + +.SH PARAMETERS + +For read-write parameters, the following describes only the write direction, +i.e. as used with the \fBset\fR command. For the \fBshow\fR command, the +parameter name is to be used as a simple keyword without further arguments. This +instructs the tool to show the value of a given parameter. When no parameters +are given, the tool shows the complete buffer configuration. + +.TP +.B total-size +A read-only property that shows the total device memory taken up by port +buffers. This might be more than a simple sum of individual buffer sizes if +there are any hidden or internal buffers. + +.TP +.B prio-buffer \fIPRIO-MAP +\fIPRIO-MAP\fR uses the array parameter syntax, see +.BR dcb (8) +for details. Keys are priorities, values are buffer indices. For each priority +sets a buffer where traffic with that priority is directed to. + +.TP +.B buffer-size \fISIZE-MAP +\fISIZE-MAP\fR uses the array parameter syntax, see +.BR dcb (8) +for details. Keys are buffer indices, values are sizes of that buffer in bytes. +The sizes can use the notation documented in section PARAMETERS at +.BR tc (8). +Note that the size requested by the tool can be rounded or capped by the driver +to satisfy the requirements of the device. + +.SH EXAMPLE & USAGE + +Configure the priomap in a one-to-one fashion: + +.P +# dcb buffer set dev eth0 prio-buffer 0:0 1:1 2:2 3:3 4:4 5:5 6:6 7:7 + +Set sizes of all buffers to 10KB, except for buffer 6, which will have the size +1MB: + +.P +# dcb buffer set dev eth0 buffer-size all:10K 6:1M + +Show what was set: + +.P +# dcb buffer show dev eth0 +.br +prio-buffer 0:0 1:1 2:2 3:3 4:4 5:5 6:6 7:7 +.br +buffer-size 0:10Kb 1:10Kb 2:10Kb 3:10Kb 4:10Kb 5:10Kb 6:1Mb 7:10Kb +.br +total-size 1222Kb + +.SH EXIT STATUS +Exit status is 0 if command was successful or a positive integer upon failure. + +.SH SEE ALSO +.BR dcb (8) + +.SH REPORTING BUGS +Report any bugs to the Network Developers mailing list +.B +where the development and maintenance is primarily done. +You do not have to be subscribed to the list to send a message there. + +.SH AUTHOR +Petr Machata diff --git a/man/man8/dcb.8 b/man/man8/dcb.8 index 01febe16..e1476236 100644 --- a/man/man8/dcb.8 +++ b/man/man8/dcb.8 @@ -9,7 +9,7 @@ dcb \- show / manipulate DCB (Data Center Bridging) settings .ti -8 .B dcb .RI "[ " OPTIONS " ] " -.RB "{ " ets " | " pfc " }" +.RB "{ " buffer " | " ets " | " pfc " }" .RI "{ " COMMAND " | " help " }" .sp @@ -63,6 +63,10 @@ part of the "show" output. .SH OBJECTS +.TP +.B buffer +- Configuration of port buffers + .TP .B ets - Configuration of ETS (Enhanced Transmission Selection) @@ -115,6 +119,7 @@ other values: Exit status is 0 if command was successful or a positive integer upon failure. .SH SEE ALSO +.BR dcb-buffer (8), .BR dcb-ets (8), .BR dcb-pfc (8) .br From 117939d9bd89369b9c97283dcbdb586d8616ae07 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Fri, 11 Dec 2020 00:02:24 +0100 Subject: [PATCH 10/10] dcb: Add a subtool for the DCB maxrate object DCBNL maxrate interfaces are an extension to the 802.1q DCB interfaces and allow configuration of rate with which traffic in a given traffic class is sent. Add a dcb subtool to allow showing and tweaking of this per-TC maximum rate. For example: # dcb maxrate show dev eni1np1 tc-maxrate 0:25Gbit 1:25Gbit 2:25Gbit 3:25Gbit 4:25Gbit 5:25Gbit 6:100Gbit 7:25Gbit Signed-off-by: Petr Machata Signed-off-by: David Ahern --- dcb/Makefile | 2 +- dcb/dcb.c | 4 +- dcb/dcb.h | 4 + dcb/dcb_maxrate.c | 182 +++++++++++++++++++++++++++++++++++++++++ man/man8/dcb-maxrate.8 | 94 +++++++++++++++++++++ man/man8/dcb.8 | 7 +- 6 files changed, 290 insertions(+), 3 deletions(-) create mode 100644 dcb/dcb_maxrate.c create mode 100644 man/man8/dcb-maxrate.8 diff --git a/dcb/Makefile b/dcb/Makefile index dc84422f..4add954b 100644 --- a/dcb/Makefile +++ b/dcb/Makefile @@ -5,7 +5,7 @@ TARGETS := ifeq ($(HAVE_MNL),y) -DCBOBJ = dcb.o dcb_buffer.o dcb_ets.o dcb_pfc.o +DCBOBJ = dcb.o dcb_buffer.o dcb_ets.o dcb_maxrate.o dcb_pfc.o TARGETS += dcb endif diff --git a/dcb/dcb.c b/dcb/dcb.c index 570405a7..adec5747 100644 --- a/dcb/dcb.c +++ b/dcb/dcb.c @@ -332,7 +332,7 @@ static void dcb_help(void) fprintf(stderr, "Usage: dcb [ OPTIONS ] OBJECT { COMMAND | help }\n" " dcb [ -f | --force ] { -b | --batch } filename [ -N | --Netns ] netnsname\n" - "where OBJECT := { buffer | ets | pfc }\n" + "where OBJECT := { buffer | ets | maxrate | pfc }\n" " OPTIONS := [ -V | --Version | -i | --iec | -j | --json\n" " | -p | --pretty | -s | --statistics | -v | --verbose]\n"); } @@ -346,6 +346,8 @@ static int dcb_cmd(struct dcb *dcb, int argc, char **argv) return dcb_cmd_buffer(dcb, argc - 1, argv + 1); } else if (matches(*argv, "ets") == 0) { return dcb_cmd_ets(dcb, argc - 1, argv + 1); + } else if (matches(*argv, "maxrate") == 0) { + return dcb_cmd_maxrate(dcb, argc - 1, argv + 1); } else if (matches(*argv, "pfc") == 0) { return dcb_cmd_pfc(dcb, argc - 1, argv + 1); } diff --git a/dcb/dcb.h b/dcb/dcb.h index 0638d639..388a4204 100644 --- a/dcb/dcb.h +++ b/dcb/dcb.h @@ -50,6 +50,10 @@ int dcb_cmd_buffer(struct dcb *dcb, int argc, char **argv); int dcb_cmd_ets(struct dcb *dcb, int argc, char **argv); +/* dcb_maxrate.c */ + +int dcb_cmd_maxrate(struct dcb *dcb, int argc, char **argv); + /* dcb_pfc.c */ int dcb_cmd_pfc(struct dcb *dcb, int argc, char **argv); diff --git a/dcb/dcb_maxrate.c b/dcb/dcb_maxrate.c new file mode 100644 index 00000000..1538c6d7 --- /dev/null +++ b/dcb/dcb_maxrate.c @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include +#include +#include +#include + +#include "dcb.h" +#include "utils.h" + +static void dcb_maxrate_help_set(void) +{ + fprintf(stderr, + "Usage: dcb maxrate set dev STRING\n" + " [ tc-maxrate RATE-MAP ]\n" + "\n" + " where RATE-MAP := [ RATE-MAP ] RATE-MAPPING\n" + " RATE-MAPPING := { all | TC }:RATE\n" + " TC := { 0 .. 7 }\n" + "\n" + ); +} + +static void dcb_maxrate_help_show(void) +{ + fprintf(stderr, + "Usage: dcb [ -i ] maxrate show dev STRING\n" + " [ tc-maxrate ]\n" + "\n" + ); +} + +static void dcb_maxrate_help(void) +{ + fprintf(stderr, + "Usage: dcb maxrate help\n" + "\n" + ); + dcb_maxrate_help_show(); + dcb_maxrate_help_set(); +} + +static int dcb_maxrate_parse_mapping_tc_maxrate(__u32 key, char *value, void *data) +{ + __u64 rate; + + if (get_rate64(&rate, value)) + return -EINVAL; + + return dcb_parse_mapping("TC", key, IEEE_8021QAZ_MAX_TCS - 1, + "RATE", rate, -1, + dcb_set_u64, data); +} + +static void dcb_maxrate_print_tc_maxrate(struct dcb *dcb, const struct ieee_maxrate *maxrate) +{ + size_t size = ARRAY_SIZE(maxrate->tc_maxrate); + SPRINT_BUF(b); + size_t i; + + open_json_array(PRINT_JSON, "tc_maxrate"); + print_string(PRINT_FP, NULL, "tc-maxrate ", NULL); + + for (i = 0; i < size; i++) { + snprintf(b, sizeof(b), "%zd:%%s ", i); + print_rate(dcb->use_iec, PRINT_ANY, NULL, b, maxrate->tc_maxrate[i]); + } + + close_json_array(PRINT_JSON, "tc_maxrate"); +} + +static void dcb_maxrate_print(struct dcb *dcb, const struct ieee_maxrate *maxrate) +{ + dcb_maxrate_print_tc_maxrate(dcb, maxrate); + print_nl(); +} + +static int dcb_maxrate_get(struct dcb *dcb, const char *dev, struct ieee_maxrate *maxrate) +{ + return dcb_get_attribute(dcb, dev, DCB_ATTR_IEEE_MAXRATE, maxrate, sizeof(*maxrate)); +} + +static int dcb_maxrate_set(struct dcb *dcb, const char *dev, const struct ieee_maxrate *maxrate) +{ + return dcb_set_attribute(dcb, dev, DCB_ATTR_IEEE_MAXRATE, maxrate, sizeof(*maxrate)); +} + +static int dcb_cmd_maxrate_set(struct dcb *dcb, const char *dev, int argc, char **argv) +{ + struct ieee_maxrate maxrate; + int ret; + + if (!argc) { + dcb_maxrate_help_set(); + return 0; + } + + ret = dcb_maxrate_get(dcb, dev, &maxrate); + if (ret) + return ret; + + do { + if (matches(*argv, "help") == 0) { + dcb_maxrate_help_set(); + return 0; + } else if (matches(*argv, "tc-maxrate") == 0) { + NEXT_ARG(); + ret = parse_mapping(&argc, &argv, true, + &dcb_maxrate_parse_mapping_tc_maxrate, &maxrate); + if (ret) { + fprintf(stderr, "Invalid mapping %s\n", *argv); + return ret; + } + continue; + } else { + fprintf(stderr, "What is \"%s\"?\n", *argv); + dcb_maxrate_help_set(); + return -EINVAL; + } + + NEXT_ARG_FWD(); + } while (argc > 0); + + return dcb_maxrate_set(dcb, dev, &maxrate); +} + +static int dcb_cmd_maxrate_show(struct dcb *dcb, const char *dev, int argc, char **argv) +{ + struct ieee_maxrate maxrate; + int ret; + + ret = dcb_maxrate_get(dcb, dev, &maxrate); + if (ret) + return ret; + + open_json_object(NULL); + + if (!argc) { + dcb_maxrate_print(dcb, &maxrate); + goto out; + } + + do { + if (matches(*argv, "help") == 0) { + dcb_maxrate_help_show(); + return 0; + } else if (matches(*argv, "tc-maxrate") == 0) { + dcb_maxrate_print_tc_maxrate(dcb, &maxrate); + print_nl(); + } else { + fprintf(stderr, "What is \"%s\"?\n", *argv); + dcb_maxrate_help_show(); + return -EINVAL; + } + + NEXT_ARG_FWD(); + } while (argc > 0); + +out: + close_json_object(); + return 0; +} + +int dcb_cmd_maxrate(struct dcb *dcb, int argc, char **argv) +{ + if (!argc || matches(*argv, "help") == 0) { + dcb_maxrate_help(); + return 0; + } else if (matches(*argv, "show") == 0) { + NEXT_ARG_FWD(); + return dcb_cmd_parse_dev(dcb, argc, argv, + dcb_cmd_maxrate_show, dcb_maxrate_help_show); + } else if (matches(*argv, "set") == 0) { + NEXT_ARG_FWD(); + return dcb_cmd_parse_dev(dcb, argc, argv, + dcb_cmd_maxrate_set, dcb_maxrate_help_set); + } else { + fprintf(stderr, "What is \"%s\"?\n", *argv); + dcb_maxrate_help(); + return -EINVAL; + } +} diff --git a/man/man8/dcb-maxrate.8 b/man/man8/dcb-maxrate.8 new file mode 100644 index 00000000..d03c215c --- /dev/null +++ b/man/man8/dcb-maxrate.8 @@ -0,0 +1,94 @@ +.TH DCB-MAXRATE 8 "22 November 2020" "iproute2" "Linux" +.SH NAME +dcb-maxrate \- show / manipulate port maxrate settings of +the DCB (Data Center Bridging) subsystem +.SH SYNOPSIS +.sp +.ad l +.in +8 + +.ti -8 +.B dcb +.RI "[ " OPTIONS " ] " +.B maxrate +.RI "{ " COMMAND " | " help " }" +.sp + +.ti -8 +.B dcb maxrate show dev +.RI DEV +.RB "[ " tc-maxrate " ]" + +.ti -8 +.B dcb maxrate set dev +.RI DEV +.RB "[ " tc-maxrate " " \fIRATE-MAP " ]" + +.ti -8 +.IR RATE-MAP " := [ " RATE-MAP " ] " RATE-MAPPING + +.ti -8 +.IR RATE-MAPPING " := { " TC " | " \fBall " }" \fB:\fIRATE\fR + +.ti -8 +.IR TC " := { " \fB0\fR " .. " \fB7\fR " }" + +.ti -8 +.IR RATE " := { " INTEGER "[" \fBbit\fR "] | " INTEGER\fBKbit\fR " | " +.IR INTEGER\fBMib\fR " | " ... " }" + +.SH DESCRIPTION + +.B dcb maxrate +is used to configure and inspect maximum rate at which traffic is allowed to +egress from a given traffic class. + +.SH PARAMETERS + +The following describes only the write direction, i.e. as used with the +\fBset\fR command. For the \fBshow\fR command, the parameter name is to be used +as a simple keyword without further arguments. This instructs the tool to show +the value of a given parameter. When no parameters are given, the tool shows the +complete maxrate configuration. + +.TP +.B tc-maxrate \fIRATE-MAP +\fIRATE-MAP\fR uses the array parameter syntax, see +.BR dcb (8) +for details. Keys are TC indices, values are traffic rates in bits per second. +The rates can use the notation documented in section PARAMETERS at +.BR tc (8). +Note that under that notation, "bit" stands for bits per second whereas "b" +stands for bytes per second. When showing, the command line option +.B -i +toggles between using decadic and ISO/IEC prefixes. + +.SH EXAMPLE & USAGE + +Set rates of all traffic classes to 25Gbps, except for TC 6, which will +have the rate of 100Gbps: + +.P +# dcb maxrate set dev eth0 tc-maxrate all:25Gbit 6:100Gbit + +Show what was set: + +.P +# dcb maxrate show dev eth0 +.br +tc-maxrate 0:25Gbit 1:25Gbit 2:25Gbit 3:25Gbit 4:25Gbit 5:25Gbit 6:100Gbit 7:25Gbit + +.SH EXIT STATUS +Exit status is 0 if command was successful or a positive integer upon failure. + +.SH SEE ALSO +.BR dcb (8) + +.SH REPORTING BUGS +Report any bugs to the Network Developers mailing list +.B +where the development and maintenance is primarily done. +You do not have to be subscribed to the list to send a message there. + +.SH AUTHOR +Petr Machata diff --git a/man/man8/dcb.8 b/man/man8/dcb.8 index e1476236..5964f25d 100644 --- a/man/man8/dcb.8 +++ b/man/man8/dcb.8 @@ -9,7 +9,7 @@ dcb \- show / manipulate DCB (Data Center Bridging) settings .ti -8 .B dcb .RI "[ " OPTIONS " ] " -.RB "{ " buffer " | " ets " | " pfc " }" +.RB "{ " buffer " | " ets " | " maxrate " | " pfc " }" .RI "{ " COMMAND " | " help " }" .sp @@ -71,6 +71,10 @@ part of the "show" output. .B ets - Configuration of ETS (Enhanced Transmission Selection) +.TP +.B maxrate +- Configuration of per-TC maximum transmit rate + .TP .B pfc - Configuration of PFC (Priority-based Flow Control) @@ -121,6 +125,7 @@ Exit status is 0 if command was successful or a positive integer upon failure. .SH SEE ALSO .BR dcb-buffer (8), .BR dcb-ets (8), +.BR dcb-maxrate (8), .BR dcb-pfc (8) .br