diff options
author | Petr Machata <me@pmachata.org> | 2021-01-02 01:03:41 +0100 |
---|---|---|
committer | David Ahern <dsahern@kernel.org> | 2021-01-18 04:09:29 +0000 |
commit | 89d11ea596498841a8e0e93643cb3141fb8e6e14 (patch) | |
tree | 3c070ea8d61e3e0c56e87584b33e66683b2b94a3 /dcb | |
parent | 8e9bed1493f5649232b063a1c12331cf8f517491 (diff) | |
download | iproute2-89d11ea596498841a8e0e93643cb3141fb8e6e14.tar.gz |
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>
Diffstat (limited to 'dcb')
-rw-r--r-- | dcb/Makefile | 1 | ||||
-rw-r--r-- | dcb/dcb.c | 4 | ||||
-rw-r--r-- | dcb/dcb.h | 4 | ||||
-rw-r--r-- | dcb/dcb_dcbx.c | 192 |
4 files changed, 200 insertions, 1 deletions
diff --git a/dcb/Makefile b/dcb/Makefile index 13d45f2b..02d5d044 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 @@ -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); diff --git a/dcb/dcb_dcbx.c b/dcb/dcb_dcbx.c new file mode 100644 index 00000000..244b671b --- /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; + } +} |