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 <m...@pmachata.org> --- dcb/Makefile | 1 + dcb/dcb.c | 4 +- dcb/dcb.h | 4 + dcb/dcb_dcbx.c | 192 ++++++++++++++++++++++++++++++++++++++++++++ man/man8/dcb-dcbx.8 | 108 +++++++++++++++++++++++++ 5 files changed, 308 insertions(+), 1 deletion(-) create mode 100644 dcb/dcb_dcbx.c create mode 100644 man/man8/dcb-dcbx.8 diff --git a/dcb/Makefile b/dcb/Makefile index 13d45f2b96b1..02d5d044cf09 100644 --- a/dcb/Makefile +++ b/dcb/Makefile @@ -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 diff --git a/dcb/dcb.c b/dcb/dcb.c index 85e40a7e0d0b..264b553c4b26 100644 --- a/dcb/dcb.c +++ b/dcb/dcb.c @@ -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 | --no-nice-names | -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) { diff --git a/dcb/dcb.h b/dcb/dcb.h index c4993d689656..e5829682c32a 100644 --- a/dcb/dcb.h +++ b/dcb/dcb.h @@ -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); diff --git a/dcb/dcb_dcbx.c b/dcb/dcb_dcbx.c new file mode 100644 index 000000000000..244b671b893b --- /dev/null +++ b/dcb/dcb_dcbx.c @@ -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; + } +} diff --git a/man/man8/dcb-dcbx.8 b/man/man8/dcb-dcbx.8 new file mode 100644 index 000000000000..52133e348a70 --- /dev/null +++ b/man/man8/dcb-dcbx.8 @@ -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 <m...@pmachata.org> -- 2.25.1