Merge branch 'dcb-pfc-buffer-maxrate' into next

Petr Machata  says:
====================

Add support to the dcb tool for the following three DCB objects:

- PFC, for "Priority-based Flow Control", allows configuration of priority
  lossiness, and related toggles.

- DCBNL buffer interfaces are an extension to the 802.1q DCB interfaces and
  allow configuration of port headroom buffers.

- 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.

Patches #1-#4 fix small issues in the current DCB code and man pages.

Patch #5 adds new helpers to the DCB dispatcher.

Patches #6 and #7 add support for command line arguments -s and -i. These
enable, respectively, display of statistical counters, and ISO/IEC mode of
rate units.

Patches #8-#10 add the subtools themselves and their man pages.

====================

Signed-off-by: David Ahern <dsahern@gmail.com>
This commit is contained in:
David Ahern 2020-12-14 16:48:38 +00:00
commit ee50fd58dc
12 changed files with 1173 additions and 22 deletions

View File

@ -5,7 +5,7 @@ TARGETS :=
ifeq ($(HAVE_MNL),y) 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 TARGETS += dcb
endif endif

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+ // SPDX-License-Identifier: GPL-2.0+
#include <inttypes.h>
#include <stdio.h> #include <stdio.h>
#include <linux/dcbnl.h> #include <linux/dcbnl.h>
#include <libmnl/libmnl.h> #include <libmnl/libmnl.h>
@ -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, void dcb_print_array_kw(const __u8 *array, size_t array_size,
const char *const kw[], size_t kw_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, int dcb_parse_mapping(const char *what_key, __u32 key, __u32 max_key,
const char *what_value, __u32 value, __u32 max_value, const char *what_value, __u64 value, __u64 max_value,
void (*set_array)(__u32 index, __u32 value, void *data), void (*set_array)(__u32 index, __u64 value, void *data),
void *set_array_data) void *set_array_data)
{ {
bool is_all = key == (__u32) -1; 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) { 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); what_key, what_value, what_value, max_value);
return -EINVAL; return -EINVAL;
} }
@ -257,13 +280,27 @@ int dcb_parse_mapping(const char *what_key, __u32 key, __u32 max_key,
return 0; 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; __u8 *array = data;
array[key] = value; 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 dcb_cmd_parse_dev(struct dcb *dcb, int argc, char **argv,
int (*and_then)(struct dcb *dcb, const char *dev, int (*and_then)(struct dcb *dcb, const char *dev,
int argc, char **argv), int argc, char **argv),
@ -295,8 +332,9 @@ static void dcb_help(void)
fprintf(stderr, fprintf(stderr,
"Usage: dcb [ OPTIONS ] OBJECT { COMMAND | help }\n" "Usage: dcb [ OPTIONS ] OBJECT { COMMAND | help }\n"
" dcb [ -f | --force ] { -b | --batch } filename [ -N | --Netns ] netnsname\n" " dcb [ -f | --force ] { -b | --batch } filename [ -N | --Netns ] netnsname\n"
"where OBJECT := ets\n" "where OBJECT := { buffer | ets | maxrate | pfc }\n"
" OPTIONS := [ -V | --Version | -j | --json | -p | --pretty | -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) 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) { if (!argc || matches(*argv, "help") == 0) {
dcb_help(); dcb_help();
return 0; return 0;
} else if (matches(*argv, "buffer") == 0) {
return dcb_cmd_buffer(dcb, argc - 1, argv + 1);
} else if (matches(*argv, "ets") == 0) { } else if (matches(*argv, "ets") == 0) {
return dcb_cmd_ets(dcb, argc - 1, argv + 1); 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); fprintf(stderr, "Object \"%s\" is unknown\n", *argv);
@ -330,8 +374,10 @@ int main(int argc, char **argv)
{ "Version", no_argument, NULL, 'V' }, { "Version", no_argument, NULL, 'V' },
{ "force", no_argument, NULL, 'f' }, { "force", no_argument, NULL, 'f' },
{ "batch", required_argument, NULL, 'b' }, { "batch", required_argument, NULL, 'b' },
{ "iec", no_argument, NULL, 'i' },
{ "json", no_argument, NULL, 'j' }, { "json", no_argument, NULL, 'j' },
{ "pretty", no_argument, NULL, 'p' }, { "pretty", no_argument, NULL, 'p' },
{ "statistics", no_argument, NULL, 's' },
{ "Netns", required_argument, NULL, 'N' }, { "Netns", required_argument, NULL, 'N' },
{ "help", no_argument, NULL, 'h' }, { "help", no_argument, NULL, 'h' },
{ NULL, 0, NULL, 0 } { NULL, 0, NULL, 0 }
@ -349,7 +395,7 @@ int main(int argc, char **argv)
return EXIT_FAILURE; 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) { long_options, NULL)) >= 0) {
switch (opt) { switch (opt) {
@ -369,12 +415,18 @@ int main(int argc, char **argv)
case 'p': case 'p':
pretty = true; pretty = true;
break; break;
case 's':
dcb->stats = true;
break;
case 'N': case 'N':
if (netns_switch(optarg)) { if (netns_switch(optarg)) {
ret = EXIT_FAILURE; ret = EXIT_FAILURE;
goto dcb_free; goto dcb_free;
} }
break; break;
case 'i':
dcb->use_iec = true;
break;
case 'h': case 'h':
dcb_help(); dcb_help();
return 0; return 0;

View File

@ -11,18 +11,22 @@ struct dcb {
char *buf; char *buf;
struct mnl_socket *nl; struct mnl_socket *nl;
bool json_output; bool json_output;
bool stats;
bool use_iec;
}; };
int dcb_parse_mapping(const char *what_key, __u32 key, __u32 max_key, int dcb_parse_mapping(const char *what_key, __u32 key, __u32 max_key,
const char *what_value, __u32 value, __u32 max_value, const char *what_value, __u64 value, __u64 max_value,
void (*set_array)(__u32 index, __u32 value, void *data), void (*set_array)(__u32 index, __u64 value, void *data),
void *set_array_data); void *set_array_data);
int dcb_cmd_parse_dev(struct dcb *dcb, int argc, char **argv, int dcb_cmd_parse_dev(struct dcb *dcb, int argc, char **argv,
int (*and_then)(struct dcb *dcb, const char *dev, int (*and_then)(struct dcb *dcb, const char *dev,
int argc, char **argv), int argc, char **argv),
void (*help)(void)); 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, int dcb_get_attribute(struct dcb *dcb, const char *dev, int attr,
void *data, size_t data_len); 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, const __u8 *array, size_t size,
void (*print_array)(const __u8 *, size_t)); void (*print_array)(const __u8 *, size_t));
void dcb_print_array_u8(const __u8 *array, size_t size); 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, void dcb_print_array_kw(const __u8 *array, size_t array_size,
const char *const kw[], size_t kw_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 */ /* dcb_ets.c */
int dcb_cmd_ets(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);
#endif /* __DCB_H__ */ #endif /* __DCB_H__ */

235
dcb/dcb_buffer.c Normal file
View File

@ -0,0 +1,235 @@
// SPDX-License-Identifier: GPL-2.0+
#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <linux/dcbnl.h>
#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;
}
}

View File

@ -32,9 +32,9 @@ static void dcb_ets_help_show(void)
{ {
fprintf(stderr, fprintf(stderr,
"Usage: dcb ets show dev STRING\n" "Usage: dcb ets show dev STRING\n"
" [ willing | ets-cap | cbs | tc-tsa | reco-tc-tsa |\n" " [ willing ] [ ets-cap ] [ cbs ] [ tc-tsa ]\n"
" pg-bw | tc-bw | reco-tc-bw | prio-tc |\n" " [ reco-tc-tsa ] [ pg-bw ] [ tc-bw ] [ reco-tc-bw ]\n"
" reco-prio-tc ]\n" " [ prio-tc ] [ reco-prio-tc ]\n"
"\n" "\n"
); );
} }
@ -370,7 +370,7 @@ static int dcb_cmd_ets_show(struct dcb *dcb, const char *dev, int argc, char **a
do { do {
if (matches(*argv, "help") == 0) { if (matches(*argv, "help") == 0) {
dcb_ets_help(); dcb_ets_help_show();
return 0; return 0;
} else if (matches(*argv, "willing") == 0) { } else if (matches(*argv, "willing") == 0) {
dcb_ets_print_willing(&ets); 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(); print_nl();
} else { } else {
fprintf(stderr, "What is \"%s\"?\n", *argv); fprintf(stderr, "What is \"%s\"?\n", *argv);
dcb_ets_help(); dcb_ets_help_show();
return -EINVAL; return -EINVAL;
} }

182
dcb/dcb_maxrate.c Normal file
View File

@ -0,0 +1,182 @@
// SPDX-License-Identifier: GPL-2.0+
#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <linux/dcbnl.h>
#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;
}
}

286
dcb/dcb_pfc.c Normal file
View File

@ -0,0 +1,286 @@
// SPDX-License-Identifier: GPL-2.0+
#include <errno.h>
#include <stdio.h>
#include <linux/dcbnl.h>
#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;
}
}

126
man/man8/dcb-buffer.8 Normal file
View File

@ -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 <netdev@vger.kernel.org>
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 <me@pmachata.org>

View File

@ -17,9 +17,16 @@ the DCB (Data Center Bridging) subsystem
.ti -8 .ti -8
.B dcb ets show dev .B dcb ets show dev
.RI DEV .RI DEV
.RB "[ { " willing " | " ets-cap " | " cbs " | " tc-tsa " | " reco-tc-tsa .RB "[ " willing " ]"
.RB " | " pg-bw " | " tc-bw " | " reco-tc-bw " | " prio-tc .RB "[ " ets-cap " ]"
.RB " | " reco-prio-tc " } ]" .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 .ti -8
.B dcb ets set dev .B dcb ets set dev
@ -54,7 +61,6 @@ the DCB (Data Center Bridging) subsystem
.ti -8 .ti -8
.IR PRIO " := { " \fB0\fR " .. " \fB7\fR " }" .IR PRIO " := { " \fB0\fR " .. " \fB7\fR " }"
.SH DESCRIPTION .SH DESCRIPTION
.B dcb ets .B dcb ets

94
man/man8/dcb-maxrate.8 Normal file
View File

@ -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 <netdev@vger.kernel.org>
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 <me@pmachata.org>

127
man/man8/dcb-pfc.8 Normal file
View File

@ -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 <netdev@vger.kernel.org>
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 <me@pmachata.org>

View File

@ -9,7 +9,7 @@ dcb \- show / manipulate DCB (Data Center Bridging) settings
.ti -8 .ti -8
.B dcb .B dcb
.RI "[ " OPTIONS " ] " .RI "[ " OPTIONS " ] "
.B ets .RB "{ " buffer " | " ets " | " maxrate " | " pfc " }"
.RI "{ " COMMAND " | " help " }" .RI "{ " COMMAND " | " help " }"
.sp .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 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. 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 .TP
.BR "\-j" , " --json" .BR "\-j" , " --json"
Generate JSON output. Generate JSON output.
@ -51,12 +56,29 @@ Generate JSON output.
.BR "\-p" , " --pretty" .BR "\-p" , " --pretty"
When combined with -j generate a pretty JSON output. 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 .SH OBJECTS
.TP
.B buffer
- Configuration of port buffers
.TP .TP
.B ets .B ets
- Configuration of ETS (Enhanced Transmission Selection) - 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 .SH COMMANDS
A \fICOMMAND\fR specifies the action to perform on the object. The set of 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. Exit status is 0 if command was successful or a positive integer upon failure.
.SH SEE ALSO .SH SEE ALSO
.BR dcb-ets (8) .BR dcb-buffer (8),
.BR dcb-ets (8),
.BR dcb-maxrate (8),
.BR dcb-pfc (8)
.br .br
.SH REPORTING BUGS .SH REPORTING BUGS