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 <me@pmachata.org>
Signed-off-by: David Ahern <dsahern@gmail.com>
This commit is contained in:
Petr Machata 2020-12-11 00:02:23 +01:00 committed by David Ahern
parent 6567cb588b
commit 2e36f91000
6 changed files with 375 additions and 3 deletions

View File

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

View File

@ -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) {

View File

@ -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);

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;
}
}

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

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