diff --git a/dcb/Makefile b/dcb/Makefile index 89581716..4add954b 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_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 dc1e9fe0..adec5747 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) { @@ -229,8 +252,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 +265,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 +280,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), @@ -295,8 +332,9 @@ 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" - " OPTIONS := [ -V | --Version | -j | --json | -p | --pretty | -v | --verbose ]\n"); + "where OBJECT := { buffer | ets | maxrate | pfc }\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) @@ -304,8 +342,14 @@ 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, "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); } fprintf(stderr, "Object \"%s\" is unknown\n", *argv); @@ -330,8 +374,10 @@ 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' }, { "Netns", required_argument, NULL, 'N' }, { "help", no_argument, NULL, 'h' }, { NULL, 0, NULL, 0 } @@ -349,7 +395,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:fhijpsvN:V", long_options, NULL)) >= 0) { switch (opt) { @@ -369,12 +415,18 @@ 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; 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 6f135ed0..388a4204 100644 --- a/dcb/dcb.h +++ b/dcb/dcb.h @@ -11,18 +11,22 @@ struct dcb { char *buf; 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, - 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); @@ -33,11 +37,25 @@ 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); +/* 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); +/* 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); + #endif /* __DCB_H__ */ 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/dcb/dcb_ets.c b/dcb/dcb_ets.c index 1735885a..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" ); } @@ -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; } 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/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-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-ets.8 b/man/man8/dcb-ets.8 index 0ae3587c..9c64b33e 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 @@ -54,7 +61,6 @@ the DCB (Data Center Bridging) subsystem .ti -8 .IR PRIO " := { " \fB0\fR " .. " \fB7\fR " }" - .SH DESCRIPTION .B dcb ets 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-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 f318435c..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 " ] " -.B ets +.RB "{ " buffer " | " ets " | " maxrate " | " pfc " }" .RI "{ " COMMAND " | " help " }" .sp @@ -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. @@ -51,12 +56,29 @@ 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 +.B buffer +- Configuration of port buffers + .TP .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) + .SH COMMANDS A \fICOMMAND\fR specifies the action to perform on the object. The set of @@ -101,7 +123,10 @@ 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-buffer (8), +.BR dcb-ets (8), +.BR dcb-maxrate (8), +.BR dcb-pfc (8) .br .SH REPORTING BUGS