dcb: Add a subtool for the DCBX object
The Linux DCBX object is a 1-byte bitfield of flags that configure whether the DCBX protocol is implemented in the device or in the host, and which version of the protocol should be used. Add a tool to access the per-port Linux DCBX object. For example: # dcb dcbx set dev eni1np1 host ieee # dcb dcbx show dev eni1np1 host ieee Signed-off-by: Petr Machata <me@pmachata.org> Signed-off-by: David Ahern <dsahern@kernel.org>
This commit is contained in:
parent
8e9bed1493
commit
89d11ea596
|
|
@ -8,6 +8,7 @@ ifeq ($(HAVE_MNL),y)
|
|||
DCBOBJ = dcb.o \
|
||||
dcb_app.o \
|
||||
dcb_buffer.o \
|
||||
dcb_dcbx.o \
|
||||
dcb_ets.o \
|
||||
dcb_maxrate.o \
|
||||
dcb_pfc.o
|
||||
|
|
|
|||
|
|
@ -465,7 +465,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 := { app | buffer | ets | maxrate | pfc }\n"
|
||||
"where OBJECT := { app | buffer | dcbx | ets | maxrate | pfc }\n"
|
||||
" OPTIONS := [ -V | --Version | -i | --iec | -j | --json\n"
|
||||
" | -N | --Numeric | -p | --pretty\n"
|
||||
" | -s | --statistics | -v | --verbose]\n");
|
||||
|
|
@ -480,6 +480,8 @@ static int dcb_cmd(struct dcb *dcb, int argc, char **argv)
|
|||
return dcb_cmd_app(dcb, argc - 1, argv + 1);
|
||||
} else if (matches(*argv, "buffer") == 0) {
|
||||
return dcb_cmd_buffer(dcb, argc - 1, argv + 1);
|
||||
} else if (matches(*argv, "dcbx") == 0) {
|
||||
return dcb_cmd_dcbx(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) {
|
||||
|
|
|
|||
|
|
@ -62,6 +62,10 @@ int dcb_cmd_app(struct dcb *dcb, int argc, char **argv);
|
|||
|
||||
int dcb_cmd_buffer(struct dcb *dcb, int argc, char **argv);
|
||||
|
||||
/* dcb_dcbx.c */
|
||||
|
||||
int dcb_cmd_dcbx(struct dcb *dcb, int argc, char **argv);
|
||||
|
||||
/* dcb_ets.c */
|
||||
|
||||
int dcb_cmd_ets(struct dcb *dcb, int argc, char **argv);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,192 @@
|
|||
// 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_dcbx_help_set(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: dcb dcbx set dev STRING\n"
|
||||
" [ host | lld-managed ]\n"
|
||||
" [ cee | ieee ] [ static ]\n"
|
||||
"\n"
|
||||
);
|
||||
}
|
||||
|
||||
static void dcb_dcbx_help_show(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: dcb dcbx show dev STRING\n"
|
||||
"\n"
|
||||
);
|
||||
}
|
||||
|
||||
static void dcb_dcbx_help(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: dcb dcbx help\n"
|
||||
"\n"
|
||||
);
|
||||
dcb_dcbx_help_show();
|
||||
dcb_dcbx_help_set();
|
||||
}
|
||||
|
||||
struct dcb_dcbx_flag {
|
||||
__u8 value;
|
||||
const char *key_fp;
|
||||
const char *key_json;
|
||||
};
|
||||
|
||||
static struct dcb_dcbx_flag dcb_dcbx_flags[] = {
|
||||
{DCB_CAP_DCBX_HOST, "host"},
|
||||
{DCB_CAP_DCBX_LLD_MANAGED, "lld-managed", "lld_managed"},
|
||||
{DCB_CAP_DCBX_VER_CEE, "cee"},
|
||||
{DCB_CAP_DCBX_VER_IEEE, "ieee"},
|
||||
{DCB_CAP_DCBX_STATIC, "static"},
|
||||
};
|
||||
|
||||
static void dcb_dcbx_print(__u8 dcbx)
|
||||
{
|
||||
int bit;
|
||||
int i;
|
||||
|
||||
while ((bit = ffs(dcbx))) {
|
||||
bool found = false;
|
||||
|
||||
bit--;
|
||||
for (i = 0; i < ARRAY_SIZE(dcb_dcbx_flags); i++) {
|
||||
struct dcb_dcbx_flag *flag = &dcb_dcbx_flags[i];
|
||||
|
||||
if (flag->value == 1 << bit) {
|
||||
print_bool(PRINT_JSON, flag->key_json ?: flag->key_fp,
|
||||
NULL, true);
|
||||
print_string(PRINT_FP, NULL, "%s ", flag->key_fp);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
fprintf(stderr, "Unknown DCBX bit %#x.\n", 1 << bit);
|
||||
|
||||
dcbx &= ~(1 << bit);
|
||||
}
|
||||
|
||||
print_nl();
|
||||
}
|
||||
|
||||
static int dcb_dcbx_get(struct dcb *dcb, const char *dev, __u8 *dcbx)
|
||||
{
|
||||
__u16 payload_len;
|
||||
void *payload;
|
||||
int err;
|
||||
|
||||
err = dcb_get_attribute_bare(dcb, DCB_CMD_IEEE_GET, dev, DCB_ATTR_DCBX,
|
||||
&payload, &payload_len);
|
||||
if (err != 0)
|
||||
return err;
|
||||
|
||||
if (payload_len != 1) {
|
||||
fprintf(stderr, "DCB_ATTR_DCBX payload has size %d, expected 1.\n",
|
||||
payload_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
*dcbx = *(__u8 *) payload;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dcb_dcbx_set(struct dcb *dcb, const char *dev, __u8 dcbx)
|
||||
{
|
||||
return dcb_set_attribute_bare(dcb, DCB_CMD_SDCBX, dev, DCB_ATTR_DCBX,
|
||||
&dcbx, 1, DCB_ATTR_DCBX);
|
||||
}
|
||||
|
||||
static int dcb_cmd_dcbx_set(struct dcb *dcb, const char *dev, int argc, char **argv)
|
||||
{
|
||||
__u8 dcbx = 0;
|
||||
__u8 i;
|
||||
|
||||
if (!argc) {
|
||||
dcb_dcbx_help_set();
|
||||
return 0;
|
||||
}
|
||||
|
||||
do {
|
||||
if (matches(*argv, "help") == 0) {
|
||||
dcb_dcbx_help_set();
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dcb_dcbx_flags); i++) {
|
||||
struct dcb_dcbx_flag *flag = &dcb_dcbx_flags[i];
|
||||
|
||||
if (matches(*argv, flag->key_fp) == 0) {
|
||||
dcbx |= flag->value;
|
||||
NEXT_ARG_FWD();
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "What is \"%s\"?\n", *argv);
|
||||
dcb_dcbx_help_set();
|
||||
return -EINVAL;
|
||||
|
||||
next:
|
||||
;
|
||||
} while (argc > 0);
|
||||
|
||||
return dcb_dcbx_set(dcb, dev, dcbx);
|
||||
}
|
||||
|
||||
static int dcb_cmd_dcbx_show(struct dcb *dcb, const char *dev, int argc, char **argv)
|
||||
{
|
||||
__u8 dcbx;
|
||||
int ret;
|
||||
|
||||
ret = dcb_dcbx_get(dcb, dev, &dcbx);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
while (argc > 0) {
|
||||
if (matches(*argv, "help") == 0) {
|
||||
dcb_dcbx_help_show();
|
||||
return 0;
|
||||
} else {
|
||||
fprintf(stderr, "What is \"%s\"?\n", *argv);
|
||||
dcb_dcbx_help_show();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
NEXT_ARG_FWD();
|
||||
}
|
||||
|
||||
open_json_object(NULL);
|
||||
dcb_dcbx_print(dcbx);
|
||||
close_json_object();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dcb_cmd_dcbx(struct dcb *dcb, int argc, char **argv)
|
||||
{
|
||||
if (!argc || matches(*argv, "help") == 0) {
|
||||
dcb_dcbx_help();
|
||||
return 0;
|
||||
} else if (matches(*argv, "show") == 0) {
|
||||
NEXT_ARG_FWD();
|
||||
return dcb_cmd_parse_dev(dcb, argc, argv,
|
||||
dcb_cmd_dcbx_show, dcb_dcbx_help_show);
|
||||
} else if (matches(*argv, "set") == 0) {
|
||||
NEXT_ARG_FWD();
|
||||
return dcb_cmd_parse_dev(dcb, argc, argv,
|
||||
dcb_cmd_dcbx_set, dcb_dcbx_help_set);
|
||||
} else {
|
||||
fprintf(stderr, "What is \"%s\"?\n", *argv);
|
||||
dcb_dcbx_help();
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
.TH DCB-DCBX 8 "13 December 2020" "iproute2" "Linux"
|
||||
.SH NAME
|
||||
dcb-dcbx \- show / manipulate port DCBX (Data Center Bridging eXchange)
|
||||
.SH SYNOPSIS
|
||||
.sp
|
||||
.ad l
|
||||
.in +8
|
||||
|
||||
.ti -8
|
||||
.B dcb
|
||||
.RI "[ " OPTIONS " ] "
|
||||
.B dcbx
|
||||
.RI "{ " COMMAND " | " help " }"
|
||||
.sp
|
||||
|
||||
.ti -8
|
||||
.B dcb dcbx show dev
|
||||
.RI DEV
|
||||
|
||||
.ti -8
|
||||
.B dcb dcbx set dev
|
||||
.RI DEV
|
||||
.RB "[ " host " ]"
|
||||
.RB "[ " lld-managed " ]"
|
||||
.RB "[ " cee " ]"
|
||||
.RB "[ " ieee " ]"
|
||||
.RB "[ " static " ]"
|
||||
|
||||
.SH DESCRIPTION
|
||||
|
||||
Data Center Bridging eXchange (DCBX) is a protocol used by DCB devices to
|
||||
exchange configuration information with directly connected peers. The Linux DCBX
|
||||
object is a 1-byte bitfield of flags that configure whether DCBX is implemented
|
||||
in the device or in the host, and which version of the protocol should be used.
|
||||
.B dcb dcbx
|
||||
is used to access the per-port Linux DCBX object.
|
||||
|
||||
There are two principal modes of operation: in
|
||||
.B host
|
||||
mode, DCBX protocol is implemented by the host LLDP agent, and the DCB
|
||||
interfaces are used to propagate the negotiate parameters to capable devices. In
|
||||
.B lld-managed
|
||||
mode, the configuration is handled by the device, and DCB interfaces are used
|
||||
for inspection of negotiated parameters, and can also be used to set initial
|
||||
parameters.
|
||||
|
||||
.SH PARAMETERS
|
||||
|
||||
When used with
|
||||
.B dcb dcbx set,
|
||||
the following keywords enable the corresponding configuration. The keywords that
|
||||
are not mentioned on the command line are considered disabled. When used with
|
||||
.B show,
|
||||
each enabled feature is shown by its corresponding keyword.
|
||||
|
||||
.TP
|
||||
.B host
|
||||
.TQ
|
||||
.B lld-managed
|
||||
The device is in the host mode of operation and, respectively, the lld-managed
|
||||
mode of operation, as described above. In principle these two keywords are
|
||||
mutually exclusive, but
|
||||
.B dcb dcbx
|
||||
allows setting both and lets the driver handle it as appropriate.
|
||||
|
||||
.TP
|
||||
.B cee
|
||||
.TQ
|
||||
.B ieee
|
||||
The device supports CEE (Converged Enhanced Ethernet) and, respecively, IEEE
|
||||
version of the DCB specification. Typically only one of these will be set, but
|
||||
.B dcb dcbx
|
||||
does not mandate this.
|
||||
|
||||
.TP
|
||||
.B static
|
||||
indicates the engine supports static configuration. No actual negotiation is
|
||||
performed, negotiated parameters are always the initial configuration.
|
||||
|
||||
.SH EXAMPLE & USAGE
|
||||
|
||||
Put the DCB engine into the "host" mode of operation, and use IEEE-standardized
|
||||
DCB interfaces:
|
||||
|
||||
.P
|
||||
# dcb dcbx set dev eth0 host ieee
|
||||
|
||||
Show what was set:
|
||||
|
||||
.P
|
||||
# dcb dcbx show dev eth0
|
||||
.br
|
||||
host ieee
|
||||
|
||||
.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>
|
||||
Loading…
Reference in New Issue