iproute2/devlink/devlink.c
<<
>>
Prefs
   1/*
   2 * devlink.c    Devlink tool
   3 *
   4 *              This program is free software; you can redistribute it and/or
   5 *              modify it under the terms of the GNU General Public License
   6 *              as published by the Free Software Foundation; either version
   7 *              2 of the License, or (at your option) any later version.
   8 *
   9 * Authors:     Jiri Pirko <jiri@mellanox.com>
  10 */
  11
  12#include <stdio.h>
  13#include <stdlib.h>
  14#include <stdarg.h>
  15#include <string.h>
  16#include <stdbool.h>
  17#include <unistd.h>
  18#include <getopt.h>
  19#include <limits.h>
  20#include <errno.h>
  21#include <inttypes.h>
  22#include <signal.h>
  23#include <time.h>
  24#include <netinet/in.h>
  25#include <arpa/inet.h>
  26#include <sys/sysinfo.h>
  27#define _LINUX_SYSINFO_H /* avoid collision with musl header */
  28#include <linux/genetlink.h>
  29#include <linux/devlink.h>
  30#include <linux/netlink.h>
  31#include <libmnl/libmnl.h>
  32#include <netinet/ether.h>
  33#include <sys/select.h>
  34#include <sys/socket.h>
  35#include <sys/types.h>
  36#include <sys/time.h>
  37#include <rt_names.h>
  38
  39#include "version.h"
  40#include "list.h"
  41#include "mnlg.h"
  42#include "mnl_utils.h"
  43#include "json_print.h"
  44#include "utils.h"
  45#include "namespace.h"
  46
  47#define ESWITCH_MODE_LEGACY "legacy"
  48#define ESWITCH_MODE_SWITCHDEV "switchdev"
  49#define ESWITCH_INLINE_MODE_NONE "none"
  50#define ESWITCH_INLINE_MODE_LINK "link"
  51#define ESWITCH_INLINE_MODE_NETWORK "network"
  52#define ESWITCH_INLINE_MODE_TRANSPORT "transport"
  53
  54#define ESWITCH_ENCAP_MODE_NONE "none"
  55#define ESWITCH_ENCAP_MODE_BASIC "basic"
  56
  57#define PARAM_CMODE_RUNTIME_STR "runtime"
  58#define PARAM_CMODE_DRIVERINIT_STR "driverinit"
  59#define PARAM_CMODE_PERMANENT_STR "permanent"
  60#define DL_ARGS_REQUIRED_MAX_ERR_LEN 80
  61
  62#define HEALTH_REPORTER_STATE_HEALTHY_STR "healthy"
  63#define HEALTH_REPORTER_STATE_ERROR_STR "error"
  64#define HEALTH_REPORTER_TIMESTAMP_FMT_LEN 80
  65
  66static int g_new_line_count;
  67static int g_indent_level;
  68static bool g_indent_newline;
  69
  70#define INDENT_STR_STEP 2
  71#define INDENT_STR_MAXLEN 32
  72static char g_indent_str[INDENT_STR_MAXLEN + 1] = "";
  73
  74static bool use_iec = false;
  75
  76static void __attribute__((format(printf, 1, 2)))
  77pr_err(const char *fmt, ...)
  78{
  79        va_list ap;
  80
  81        va_start(ap, fmt);
  82        vfprintf(stderr, fmt, ap);
  83        va_end(ap);
  84}
  85
  86static void __attribute__((format(printf, 1, 2)))
  87pr_out(const char *fmt, ...)
  88{
  89        va_list ap;
  90
  91        if (g_indent_newline) {
  92                printf("%s", g_indent_str);
  93                g_indent_newline = false;
  94        }
  95        va_start(ap, fmt);
  96        vprintf(fmt, ap);
  97        va_end(ap);
  98        g_new_line_count = 0;
  99}
 100
 101static void __attribute__((format(printf, 2, 3)))
 102pr_out_sp(unsigned int num, const char *fmt, ...)
 103{
 104        va_list ap;
 105        int ret;
 106
 107        va_start(ap, fmt);
 108        ret = vprintf(fmt, ap);
 109        va_end(ap);
 110
 111        if (ret < num)
 112                printf("%*s", num - ret, "");
 113        g_new_line_count = 0;                   \
 114}
 115
 116static void __attribute__((format(printf, 1, 2)))
 117pr_out_tty(const char *fmt, ...)
 118{
 119        va_list ap;
 120
 121        if (!isatty(STDOUT_FILENO))
 122                return;
 123        va_start(ap, fmt);
 124        vprintf(fmt, ap);
 125        va_end(ap);
 126}
 127
 128static void __pr_out_indent_inc(void)
 129{
 130        if (g_indent_level + INDENT_STR_STEP > INDENT_STR_MAXLEN)
 131                return;
 132        g_indent_level += INDENT_STR_STEP;
 133        memset(g_indent_str, ' ', sizeof(g_indent_str));
 134        g_indent_str[g_indent_level] = '\0';
 135}
 136
 137static void __pr_out_indent_dec(void)
 138{
 139        if (g_indent_level - INDENT_STR_STEP < 0)
 140                return;
 141        g_indent_level -= INDENT_STR_STEP;
 142        g_indent_str[g_indent_level] = '\0';
 143}
 144
 145static void __pr_out_newline(void)
 146{
 147        if (g_new_line_count < 1) {
 148                pr_out("\n");
 149                g_indent_newline = true;
 150        }
 151        g_new_line_count++;
 152}
 153
 154static void dummy_signal_handler(int signum)
 155{
 156}
 157
 158static int _mnlg_socket_recv_run_intr(struct mnlu_gen_socket *nlg,
 159                                      mnl_cb_t data_cb, void *data)
 160{
 161        struct sigaction act, oact;
 162        int err;
 163
 164        act.sa_handler = dummy_signal_handler;
 165        sigemptyset(&act.sa_mask);
 166        act.sa_flags = SA_NODEFER;
 167
 168        sigaction(SIGINT, &act, &oact);
 169        err = mnlu_gen_socket_recv_run(nlg, data_cb, data);
 170        sigaction(SIGINT, &oact, NULL);
 171        if (err < 0 && errno != EINTR) {
 172                pr_err("devlink answers: %s\n", strerror(errno));
 173                return -errno;
 174        }
 175        return 0;
 176}
 177
 178static int _mnlg_socket_send(struct mnlu_gen_socket *nlg,
 179                             const struct nlmsghdr *nlh)
 180{
 181        int err;
 182
 183        err = mnlg_socket_send(nlg, nlh);
 184        if (err < 0) {
 185                pr_err("Failed to call mnlg_socket_send\n");
 186                return -errno;
 187        }
 188        return 0;
 189}
 190
 191static int _mnlg_socket_group_add(struct mnlu_gen_socket *nlg,
 192                                  const char *group_name)
 193{
 194        int err;
 195
 196        err = mnlg_socket_group_add(nlg, group_name);
 197        if (err < 0) {
 198                pr_err("Failed to call mnlg_socket_group_add\n");
 199                return -errno;
 200        }
 201        return 0;
 202}
 203
 204struct ifname_map {
 205        struct list_head list;
 206        char *bus_name;
 207        char *dev_name;
 208        uint32_t port_index;
 209        char *ifname;
 210};
 211
 212static struct ifname_map *ifname_map_alloc(const char *bus_name,
 213                                           const char *dev_name,
 214                                           uint32_t port_index,
 215                                           const char *ifname)
 216{
 217        struct ifname_map *ifname_map;
 218
 219        ifname_map = calloc(1, sizeof(*ifname_map));
 220        if (!ifname_map)
 221                return NULL;
 222        ifname_map->bus_name = strdup(bus_name);
 223        ifname_map->dev_name = strdup(dev_name);
 224        ifname_map->port_index = port_index;
 225        ifname_map->ifname = strdup(ifname);
 226        if (!ifname_map->bus_name || !ifname_map->dev_name ||
 227            !ifname_map->ifname) {
 228                free(ifname_map->ifname);
 229                free(ifname_map->dev_name);
 230                free(ifname_map->bus_name);
 231                free(ifname_map);
 232                return NULL;
 233        }
 234        return ifname_map;
 235}
 236
 237static void ifname_map_free(struct ifname_map *ifname_map)
 238{
 239        free(ifname_map->ifname);
 240        free(ifname_map->dev_name);
 241        free(ifname_map->bus_name);
 242        free(ifname_map);
 243}
 244
 245#define DL_OPT_HANDLE           BIT(0)
 246#define DL_OPT_HANDLEP          BIT(1)
 247#define DL_OPT_PORT_TYPE        BIT(2)
 248#define DL_OPT_PORT_COUNT       BIT(3)
 249#define DL_OPT_SB               BIT(4)
 250#define DL_OPT_SB_POOL          BIT(5)
 251#define DL_OPT_SB_SIZE          BIT(6)
 252#define DL_OPT_SB_TYPE          BIT(7)
 253#define DL_OPT_SB_THTYPE        BIT(8)
 254#define DL_OPT_SB_TH            BIT(9)
 255#define DL_OPT_SB_TC            BIT(10)
 256#define DL_OPT_ESWITCH_MODE     BIT(11)
 257#define DL_OPT_ESWITCH_INLINE_MODE      BIT(12)
 258#define DL_OPT_DPIPE_TABLE_NAME BIT(13)
 259#define DL_OPT_DPIPE_TABLE_COUNTERS     BIT(14)
 260#define DL_OPT_ESWITCH_ENCAP_MODE       BIT(15)
 261#define DL_OPT_RESOURCE_PATH    BIT(16)
 262#define DL_OPT_RESOURCE_SIZE    BIT(17)
 263#define DL_OPT_PARAM_NAME       BIT(18)
 264#define DL_OPT_PARAM_VALUE      BIT(19)
 265#define DL_OPT_PARAM_CMODE      BIT(20)
 266#define DL_OPT_HANDLE_REGION            BIT(21)
 267#define DL_OPT_REGION_SNAPSHOT_ID       BIT(22)
 268#define DL_OPT_REGION_ADDRESS           BIT(23)
 269#define DL_OPT_REGION_LENGTH            BIT(24)
 270#define DL_OPT_FLASH_FILE_NAME  BIT(25)
 271#define DL_OPT_FLASH_COMPONENT  BIT(26)
 272#define DL_OPT_HEALTH_REPORTER_NAME     BIT(27)
 273#define DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD  BIT(28)
 274#define DL_OPT_HEALTH_REPORTER_AUTO_RECOVER     BIT(29)
 275#define DL_OPT_TRAP_NAME                BIT(30)
 276#define DL_OPT_TRAP_ACTION              BIT(31)
 277#define DL_OPT_TRAP_GROUP_NAME          BIT(32)
 278#define DL_OPT_NETNS    BIT(33)
 279#define DL_OPT_TRAP_POLICER_ID          BIT(34)
 280#define DL_OPT_TRAP_POLICER_RATE        BIT(35)
 281#define DL_OPT_TRAP_POLICER_BURST       BIT(36)
 282#define DL_OPT_HEALTH_REPORTER_AUTO_DUMP     BIT(37)
 283#define DL_OPT_PORT_FUNCTION_HW_ADDR BIT(38)
 284#define DL_OPT_FLASH_OVERWRITE          BIT(39)
 285#define DL_OPT_RELOAD_ACTION            BIT(40)
 286#define DL_OPT_RELOAD_LIMIT     BIT(41)
 287#define DL_OPT_PORT_FLAVOUR BIT(42)
 288#define DL_OPT_PORT_PFNUMBER BIT(43)
 289#define DL_OPT_PORT_SFNUMBER BIT(44)
 290#define DL_OPT_PORT_FUNCTION_STATE BIT(45)
 291#define DL_OPT_PORT_CONTROLLER BIT(46)
 292#define DL_OPT_PORT_FN_RATE_TYPE        BIT(47)
 293#define DL_OPT_PORT_FN_RATE_TX_SHARE    BIT(48)
 294#define DL_OPT_PORT_FN_RATE_TX_MAX      BIT(49)
 295#define DL_OPT_PORT_FN_RATE_NODE_NAME   BIT(50)
 296#define DL_OPT_PORT_FN_RATE_PARENT      BIT(51)
 297
 298struct dl_opts {
 299        uint64_t present; /* flags of present items */
 300        char *bus_name;
 301        char *dev_name;
 302        uint32_t port_index;
 303        enum devlink_port_type port_type;
 304        uint32_t port_count;
 305        uint32_t sb_index;
 306        uint16_t sb_pool_index;
 307        uint32_t sb_pool_size;
 308        enum devlink_sb_pool_type sb_pool_type;
 309        enum devlink_sb_threshold_type sb_pool_thtype;
 310        uint32_t sb_threshold;
 311        uint16_t sb_tc_index;
 312        enum devlink_eswitch_mode eswitch_mode;
 313        enum devlink_eswitch_inline_mode eswitch_inline_mode;
 314        const char *dpipe_table_name;
 315        bool dpipe_counters_enabled;
 316        enum devlink_eswitch_encap_mode eswitch_encap_mode;
 317        const char *resource_path;
 318        uint64_t resource_size;
 319        uint32_t resource_id;
 320        bool resource_id_valid;
 321        const char *param_name;
 322        const char *param_value;
 323        enum devlink_param_cmode cmode;
 324        char *region_name;
 325        uint32_t region_snapshot_id;
 326        uint64_t region_address;
 327        uint64_t region_length;
 328        const char *flash_file_name;
 329        const char *flash_component;
 330        const char *reporter_name;
 331        uint64_t reporter_graceful_period;
 332        bool reporter_auto_recover;
 333        bool reporter_auto_dump;
 334        const char *trap_name;
 335        const char *trap_group_name;
 336        enum devlink_trap_action trap_action;
 337        bool netns_is_pid;
 338        uint32_t netns;
 339        uint32_t trap_policer_id;
 340        uint64_t trap_policer_rate;
 341        uint64_t trap_policer_burst;
 342        char port_function_hw_addr[MAX_ADDR_LEN];
 343        uint32_t port_function_hw_addr_len;
 344        uint32_t overwrite_mask;
 345        enum devlink_reload_action reload_action;
 346        enum devlink_reload_limit reload_limit;
 347        uint32_t port_controller;
 348        uint32_t port_sfnumber;
 349        uint16_t port_flavour;
 350        uint16_t port_pfnumber;
 351        uint8_t port_fn_state;
 352        uint16_t rate_type;
 353        uint64_t rate_tx_share;
 354        uint64_t rate_tx_max;
 355        char *rate_node_name;
 356        const char *rate_parent_node;
 357};
 358
 359struct dl {
 360        struct mnlu_gen_socket nlg;
 361        struct list_head ifname_map_list;
 362        int argc;
 363        char **argv;
 364        bool no_nice_names;
 365        struct dl_opts opts;
 366        bool json_output;
 367        bool pretty_output;
 368        bool verbose;
 369        bool stats;
 370        struct {
 371                bool present;
 372                char *bus_name;
 373                char *dev_name;
 374                uint32_t port_index;
 375        } arr_last;
 376};
 377
 378static int dl_argc(struct dl *dl)
 379{
 380        return dl->argc;
 381}
 382
 383static char *dl_argv(struct dl *dl)
 384{
 385        if (dl_argc(dl) == 0)
 386                return NULL;
 387        return *dl->argv;
 388}
 389
 390static void dl_arg_inc(struct dl *dl)
 391{
 392        if (dl_argc(dl) == 0)
 393                return;
 394        dl->argc--;
 395        dl->argv++;
 396}
 397
 398static void dl_arg_dec(struct dl *dl)
 399{
 400        dl->argc++;
 401        dl->argv--;
 402}
 403
 404static char *dl_argv_next(struct dl *dl)
 405{
 406        char *ret;
 407
 408        if (dl_argc(dl) == 0)
 409                return NULL;
 410
 411        ret = *dl->argv;
 412        dl_arg_inc(dl);
 413        return ret;
 414}
 415
 416static char *dl_argv_index(struct dl *dl, unsigned int index)
 417{
 418        if (index >= dl_argc(dl))
 419                return NULL;
 420        return dl->argv[index];
 421}
 422
 423static int strcmpx(const char *str1, const char *str2)
 424{
 425        if (strlen(str1) > strlen(str2))
 426                return -1;
 427        return strncmp(str1, str2, strlen(str1));
 428}
 429
 430static bool dl_argv_match(struct dl *dl, const char *pattern)
 431{
 432        if (dl_argc(dl) == 0)
 433                return false;
 434        return strcmpx(dl_argv(dl), pattern) == 0;
 435}
 436
 437static bool dl_no_arg(struct dl *dl)
 438{
 439        return dl_argc(dl) == 0;
 440}
 441
 442static void __pr_out_indent_newline(struct dl *dl)
 443{
 444        if (!g_indent_newline && !dl->json_output)
 445                pr_out(" ");
 446}
 447
 448static bool is_binary_eol(int i)
 449{
 450        return !(i%16);
 451}
 452
 453static void pr_out_binary_value(struct dl *dl, uint8_t *data, uint32_t len)
 454{
 455        int i = 0;
 456
 457        while (i < len) {
 458                if (dl->json_output)
 459                        print_int(PRINT_JSON, NULL, NULL, data[i]);
 460                else
 461                        pr_out("%02x ", data[i]);
 462                i++;
 463                if (!dl->json_output && is_binary_eol(i))
 464                        __pr_out_newline();
 465        }
 466        if (!dl->json_output && !is_binary_eol(i))
 467                __pr_out_newline();
 468}
 469
 470static void pr_out_name(struct dl *dl, const char *name)
 471{
 472        __pr_out_indent_newline(dl);
 473        if (dl->json_output)
 474                print_string(PRINT_JSON, name, NULL, NULL);
 475        else
 476                pr_out("%s:", name);
 477}
 478
 479static void pr_out_u64(struct dl *dl, const char *name, uint64_t val)
 480{
 481        __pr_out_indent_newline(dl);
 482        if (val == (uint64_t) -1)
 483                return print_string_name_value(name, "unlimited");
 484
 485        if (dl->json_output)
 486                print_u64(PRINT_JSON, name, NULL, val);
 487        else
 488                pr_out("%s %"PRIu64, name, val);
 489}
 490
 491static void pr_out_section_start(struct dl *dl, const char *name)
 492{
 493        if (dl->json_output) {
 494                open_json_object(NULL);
 495                open_json_object(name);
 496        }
 497}
 498
 499static void pr_out_section_end(struct dl *dl)
 500{
 501        if (dl->json_output) {
 502                if (dl->arr_last.present)
 503                        close_json_array(PRINT_JSON, NULL);
 504                close_json_object();
 505                close_json_object();
 506        }
 507}
 508
 509static void pr_out_array_start(struct dl *dl, const char *name)
 510{
 511        if (dl->json_output) {
 512                open_json_array(PRINT_JSON, name);
 513        } else {
 514                __pr_out_indent_inc();
 515                __pr_out_newline();
 516                pr_out("%s:", name);
 517                __pr_out_indent_inc();
 518                __pr_out_newline();
 519        }
 520}
 521
 522static void pr_out_array_end(struct dl *dl)
 523{
 524        if (dl->json_output) {
 525                close_json_array(PRINT_JSON, NULL);
 526        } else {
 527                __pr_out_indent_dec();
 528                __pr_out_indent_dec();
 529        }
 530}
 531
 532static void pr_out_object_start(struct dl *dl, const char *name)
 533{
 534        if (dl->json_output) {
 535                open_json_object(name);
 536        } else {
 537                __pr_out_indent_inc();
 538                __pr_out_newline();
 539                pr_out("%s:", name);
 540                __pr_out_indent_inc();
 541                __pr_out_newline();
 542        }
 543}
 544
 545static void pr_out_object_end(struct dl *dl)
 546{
 547        if (dl->json_output) {
 548                close_json_object();
 549        } else {
 550                __pr_out_indent_dec();
 551                __pr_out_indent_dec();
 552        }
 553}
 554
 555static void pr_out_entry_start(struct dl *dl)
 556{
 557        if (dl->json_output)
 558                open_json_object(NULL);
 559}
 560
 561static void pr_out_entry_end(struct dl *dl)
 562{
 563        if (dl->json_output)
 564                close_json_object();
 565        else
 566                __pr_out_newline();
 567}
 568
 569static void check_indent_newline(struct dl *dl)
 570{
 571        __pr_out_indent_newline(dl);
 572
 573        if (g_indent_newline && !is_json_context()) {
 574                printf("%s", g_indent_str);
 575                g_indent_newline = false;
 576        }
 577        g_new_line_count = 0;
 578}
 579
 580static const enum mnl_attr_data_type devlink_policy[DEVLINK_ATTR_MAX + 1] = {
 581        [DEVLINK_ATTR_BUS_NAME] = MNL_TYPE_NUL_STRING,
 582        [DEVLINK_ATTR_DEV_NAME] = MNL_TYPE_NUL_STRING,
 583        [DEVLINK_ATTR_PORT_INDEX] = MNL_TYPE_U32,
 584        [DEVLINK_ATTR_PORT_TYPE] = MNL_TYPE_U16,
 585        [DEVLINK_ATTR_PORT_DESIRED_TYPE] = MNL_TYPE_U16,
 586        [DEVLINK_ATTR_PORT_NETDEV_IFINDEX] = MNL_TYPE_U32,
 587        [DEVLINK_ATTR_PORT_NETDEV_NAME] = MNL_TYPE_NUL_STRING,
 588        [DEVLINK_ATTR_PORT_IBDEV_NAME] = MNL_TYPE_NUL_STRING,
 589        [DEVLINK_ATTR_PORT_LANES] = MNL_TYPE_U32,
 590        [DEVLINK_ATTR_PORT_SPLITTABLE] = MNL_TYPE_U8,
 591        [DEVLINK_ATTR_SB_INDEX] = MNL_TYPE_U32,
 592        [DEVLINK_ATTR_SB_SIZE] = MNL_TYPE_U32,
 593        [DEVLINK_ATTR_SB_INGRESS_POOL_COUNT] = MNL_TYPE_U16,
 594        [DEVLINK_ATTR_SB_EGRESS_POOL_COUNT] = MNL_TYPE_U16,
 595        [DEVLINK_ATTR_SB_INGRESS_TC_COUNT] = MNL_TYPE_U16,
 596        [DEVLINK_ATTR_SB_EGRESS_TC_COUNT] = MNL_TYPE_U16,
 597        [DEVLINK_ATTR_SB_POOL_INDEX] = MNL_TYPE_U16,
 598        [DEVLINK_ATTR_SB_POOL_TYPE] = MNL_TYPE_U8,
 599        [DEVLINK_ATTR_SB_POOL_SIZE] = MNL_TYPE_U32,
 600        [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = MNL_TYPE_U8,
 601        [DEVLINK_ATTR_SB_THRESHOLD] = MNL_TYPE_U32,
 602        [DEVLINK_ATTR_SB_TC_INDEX] = MNL_TYPE_U16,
 603        [DEVLINK_ATTR_SB_OCC_CUR] = MNL_TYPE_U32,
 604        [DEVLINK_ATTR_SB_OCC_MAX] = MNL_TYPE_U32,
 605        [DEVLINK_ATTR_ESWITCH_MODE] = MNL_TYPE_U16,
 606        [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = MNL_TYPE_U8,
 607        [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = MNL_TYPE_U8,
 608        [DEVLINK_ATTR_DPIPE_TABLES] = MNL_TYPE_NESTED,
 609        [DEVLINK_ATTR_DPIPE_TABLE] = MNL_TYPE_NESTED,
 610        [DEVLINK_ATTR_DPIPE_TABLE_NAME] = MNL_TYPE_STRING,
 611        [DEVLINK_ATTR_DPIPE_TABLE_SIZE] = MNL_TYPE_U64,
 612        [DEVLINK_ATTR_DPIPE_TABLE_MATCHES] = MNL_TYPE_NESTED,
 613        [DEVLINK_ATTR_DPIPE_TABLE_ACTIONS] = MNL_TYPE_NESTED,
 614        [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] =  MNL_TYPE_U8,
 615        [DEVLINK_ATTR_DPIPE_ENTRIES] = MNL_TYPE_NESTED,
 616        [DEVLINK_ATTR_DPIPE_ENTRY] = MNL_TYPE_NESTED,
 617        [DEVLINK_ATTR_DPIPE_ENTRY_INDEX] = MNL_TYPE_U64,
 618        [DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES] = MNL_TYPE_NESTED,
 619        [DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES] = MNL_TYPE_NESTED,
 620        [DEVLINK_ATTR_DPIPE_ENTRY_COUNTER] = MNL_TYPE_U64,
 621        [DEVLINK_ATTR_DPIPE_MATCH] = MNL_TYPE_NESTED,
 622        [DEVLINK_ATTR_DPIPE_MATCH_VALUE] = MNL_TYPE_NESTED,
 623        [DEVLINK_ATTR_DPIPE_MATCH_TYPE] = MNL_TYPE_U32,
 624        [DEVLINK_ATTR_DPIPE_ACTION] = MNL_TYPE_NESTED,
 625        [DEVLINK_ATTR_DPIPE_ACTION_VALUE] = MNL_TYPE_NESTED,
 626        [DEVLINK_ATTR_DPIPE_ACTION_TYPE] = MNL_TYPE_U32,
 627        [DEVLINK_ATTR_DPIPE_VALUE_MAPPING] = MNL_TYPE_U32,
 628        [DEVLINK_ATTR_DPIPE_HEADERS] = MNL_TYPE_NESTED,
 629        [DEVLINK_ATTR_DPIPE_HEADER] = MNL_TYPE_NESTED,
 630        [DEVLINK_ATTR_DPIPE_HEADER_NAME] = MNL_TYPE_STRING,
 631        [DEVLINK_ATTR_DPIPE_HEADER_ID] = MNL_TYPE_U32,
 632        [DEVLINK_ATTR_DPIPE_HEADER_FIELDS] = MNL_TYPE_NESTED,
 633        [DEVLINK_ATTR_DPIPE_HEADER_GLOBAL] = MNL_TYPE_U8,
 634        [DEVLINK_ATTR_DPIPE_HEADER_INDEX] = MNL_TYPE_U32,
 635        [DEVLINK_ATTR_DPIPE_FIELD] = MNL_TYPE_NESTED,
 636        [DEVLINK_ATTR_DPIPE_FIELD_NAME] = MNL_TYPE_STRING,
 637        [DEVLINK_ATTR_DPIPE_FIELD_ID] = MNL_TYPE_U32,
 638        [DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH] = MNL_TYPE_U32,
 639        [DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE] = MNL_TYPE_U32,
 640        [DEVLINK_ATTR_PARAM] = MNL_TYPE_NESTED,
 641        [DEVLINK_ATTR_PARAM_NAME] = MNL_TYPE_STRING,
 642        [DEVLINK_ATTR_PARAM_TYPE] = MNL_TYPE_U8,
 643        [DEVLINK_ATTR_PARAM_VALUES_LIST] = MNL_TYPE_NESTED,
 644        [DEVLINK_ATTR_PARAM_VALUE] = MNL_TYPE_NESTED,
 645        [DEVLINK_ATTR_PARAM_VALUE_CMODE] = MNL_TYPE_U8,
 646        [DEVLINK_ATTR_REGION_NAME] = MNL_TYPE_STRING,
 647        [DEVLINK_ATTR_REGION_SIZE] = MNL_TYPE_U64,
 648        [DEVLINK_ATTR_REGION_SNAPSHOTS] = MNL_TYPE_NESTED,
 649        [DEVLINK_ATTR_REGION_SNAPSHOT] = MNL_TYPE_NESTED,
 650        [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = MNL_TYPE_U32,
 651        [DEVLINK_ATTR_REGION_CHUNKS] = MNL_TYPE_NESTED,
 652        [DEVLINK_ATTR_REGION_CHUNK] = MNL_TYPE_NESTED,
 653        [DEVLINK_ATTR_REGION_CHUNK_DATA] = MNL_TYPE_BINARY,
 654        [DEVLINK_ATTR_REGION_CHUNK_ADDR] = MNL_TYPE_U64,
 655        [DEVLINK_ATTR_REGION_CHUNK_LEN] = MNL_TYPE_U64,
 656        [DEVLINK_ATTR_INFO_DRIVER_NAME] = MNL_TYPE_STRING,
 657        [DEVLINK_ATTR_INFO_SERIAL_NUMBER] = MNL_TYPE_STRING,
 658        [DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER] = MNL_TYPE_STRING,
 659        [DEVLINK_ATTR_INFO_VERSION_FIXED] = MNL_TYPE_NESTED,
 660        [DEVLINK_ATTR_INFO_VERSION_RUNNING] = MNL_TYPE_NESTED,
 661        [DEVLINK_ATTR_INFO_VERSION_STORED] = MNL_TYPE_NESTED,
 662        [DEVLINK_ATTR_INFO_VERSION_NAME] = MNL_TYPE_STRING,
 663        [DEVLINK_ATTR_INFO_VERSION_VALUE] = MNL_TYPE_STRING,
 664        [DEVLINK_ATTR_HEALTH_REPORTER] = MNL_TYPE_NESTED,
 665        [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = MNL_TYPE_STRING,
 666        [DEVLINK_ATTR_HEALTH_REPORTER_STATE] = MNL_TYPE_U8,
 667        [DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT] = MNL_TYPE_U64,
 668        [DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT] = MNL_TYPE_U64,
 669        [DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS] = MNL_TYPE_U64,
 670        [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = MNL_TYPE_U64,
 671        [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT] = MNL_TYPE_STRING,
 672        [DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG] = MNL_TYPE_STRING,
 673        [DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE] = MNL_TYPE_U64,
 674        [DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL] = MNL_TYPE_U64,
 675        [DEVLINK_ATTR_STATS] = MNL_TYPE_NESTED,
 676        [DEVLINK_ATTR_TRAP_NAME] = MNL_TYPE_STRING,
 677        [DEVLINK_ATTR_TRAP_ACTION] = MNL_TYPE_U8,
 678        [DEVLINK_ATTR_TRAP_TYPE] = MNL_TYPE_U8,
 679        [DEVLINK_ATTR_TRAP_GENERIC] = MNL_TYPE_FLAG,
 680        [DEVLINK_ATTR_TRAP_METADATA] = MNL_TYPE_NESTED,
 681        [DEVLINK_ATTR_TRAP_GROUP_NAME] = MNL_TYPE_STRING,
 682        [DEVLINK_ATTR_RELOAD_FAILED] = MNL_TYPE_U8,
 683        [DEVLINK_ATTR_DEV_STATS] = MNL_TYPE_NESTED,
 684        [DEVLINK_ATTR_RELOAD_STATS] = MNL_TYPE_NESTED,
 685        [DEVLINK_ATTR_RELOAD_STATS_ENTRY] = MNL_TYPE_NESTED,
 686        [DEVLINK_ATTR_RELOAD_ACTION] = MNL_TYPE_U8,
 687        [DEVLINK_ATTR_RELOAD_STATS_LIMIT] = MNL_TYPE_U8,
 688        [DEVLINK_ATTR_RELOAD_STATS_VALUE] = MNL_TYPE_U32,
 689        [DEVLINK_ATTR_REMOTE_RELOAD_STATS] = MNL_TYPE_NESTED,
 690        [DEVLINK_ATTR_RELOAD_ACTION_INFO] = MNL_TYPE_NESTED,
 691        [DEVLINK_ATTR_RELOAD_ACTION_STATS] = MNL_TYPE_NESTED,
 692        [DEVLINK_ATTR_TRAP_POLICER_ID] = MNL_TYPE_U32,
 693        [DEVLINK_ATTR_TRAP_POLICER_RATE] = MNL_TYPE_U64,
 694        [DEVLINK_ATTR_TRAP_POLICER_BURST] = MNL_TYPE_U64,
 695};
 696
 697static const enum mnl_attr_data_type
 698devlink_stats_policy[DEVLINK_ATTR_STATS_MAX + 1] = {
 699        [DEVLINK_ATTR_STATS_RX_PACKETS] = MNL_TYPE_U64,
 700        [DEVLINK_ATTR_STATS_RX_BYTES] = MNL_TYPE_U64,
 701        [DEVLINK_ATTR_STATS_RX_DROPPED] = MNL_TYPE_U64,
 702};
 703
 704static int attr_cb(const struct nlattr *attr, void *data)
 705{
 706        const struct nlattr **tb = data;
 707        int type;
 708
 709        if (mnl_attr_type_valid(attr, DEVLINK_ATTR_MAX) < 0)
 710                return MNL_CB_OK;
 711
 712        type = mnl_attr_get_type(attr);
 713        if (mnl_attr_validate(attr, devlink_policy[type]) < 0)
 714                return MNL_CB_ERROR;
 715
 716        tb[type] = attr;
 717        return MNL_CB_OK;
 718}
 719
 720static int attr_stats_cb(const struct nlattr *attr, void *data)
 721{
 722        const struct nlattr **tb = data;
 723        int type;
 724
 725        /* Allow the tool to work on top of newer kernels that might contain
 726         * more attributes.
 727         */
 728        if (mnl_attr_type_valid(attr, DEVLINK_ATTR_STATS_MAX) < 0)
 729                return MNL_CB_OK;
 730
 731        type = mnl_attr_get_type(attr);
 732        if (mnl_attr_validate(attr, devlink_stats_policy[type]) < 0)
 733                return MNL_CB_ERROR;
 734
 735        tb[type] = attr;
 736        return MNL_CB_OK;
 737}
 738
 739static const enum mnl_attr_data_type
 740devlink_function_policy[DEVLINK_PORT_FUNCTION_ATTR_MAX + 1] = {
 741        [DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR ] = MNL_TYPE_BINARY,
 742        [DEVLINK_PORT_FN_ATTR_STATE] = MNL_TYPE_U8,
 743};
 744
 745static int function_attr_cb(const struct nlattr *attr, void *data)
 746{
 747        const struct nlattr **tb = data;
 748        int type;
 749
 750        /* Allow the tool to work on top of newer kernels that might contain
 751         * more attributes.
 752         */
 753        if (mnl_attr_type_valid(attr, DEVLINK_PORT_FUNCTION_ATTR_MAX) < 0)
 754                return MNL_CB_OK;
 755
 756        type = mnl_attr_get_type(attr);
 757        if (mnl_attr_validate(attr, devlink_function_policy[type]) < 0)
 758                return MNL_CB_ERROR;
 759
 760        tb[type] = attr;
 761        return MNL_CB_OK;
 762}
 763
 764static int ifname_map_cb(const struct nlmsghdr *nlh, void *data)
 765{
 766        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
 767        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
 768        struct dl *dl = data;
 769        struct ifname_map *ifname_map;
 770        const char *bus_name;
 771        const char *dev_name;
 772        uint32_t port_ifindex;
 773        const char *port_ifname;
 774
 775        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
 776        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
 777            !tb[DEVLINK_ATTR_PORT_INDEX])
 778                return MNL_CB_ERROR;
 779
 780        if (!tb[DEVLINK_ATTR_PORT_NETDEV_NAME])
 781                return MNL_CB_OK;
 782
 783        bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
 784        dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
 785        port_ifindex = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]);
 786        port_ifname = mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME]);
 787        ifname_map = ifname_map_alloc(bus_name, dev_name,
 788                                      port_ifindex, port_ifname);
 789        if (!ifname_map)
 790                return MNL_CB_ERROR;
 791        list_add(&ifname_map->list, &dl->ifname_map_list);
 792
 793        return MNL_CB_OK;
 794}
 795
 796static void ifname_map_fini(struct dl *dl)
 797{
 798        struct ifname_map *ifname_map, *tmp;
 799
 800        list_for_each_entry_safe(ifname_map, tmp,
 801                                 &dl->ifname_map_list, list) {
 802                list_del(&ifname_map->list);
 803                ifname_map_free(ifname_map);
 804        }
 805}
 806
 807static int ifname_map_init(struct dl *dl)
 808{
 809        struct nlmsghdr *nlh;
 810        int err;
 811
 812        INIT_LIST_HEAD(&dl->ifname_map_list);
 813
 814
 815        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_GET,
 816                               NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
 817
 818        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, ifname_map_cb, dl);
 819        if (err) {
 820                ifname_map_fini(dl);
 821                return err;
 822        }
 823        return 0;
 824}
 825
 826static int ifname_map_lookup(struct dl *dl, const char *ifname,
 827                             char **p_bus_name, char **p_dev_name,
 828                             uint32_t *p_port_index)
 829{
 830        struct ifname_map *ifname_map;
 831
 832        list_for_each_entry(ifname_map, &dl->ifname_map_list, list) {
 833                if (strcmp(ifname, ifname_map->ifname) == 0) {
 834                        *p_bus_name = ifname_map->bus_name;
 835                        *p_dev_name = ifname_map->dev_name;
 836                        *p_port_index = ifname_map->port_index;
 837                        return 0;
 838                }
 839        }
 840        return -ENOENT;
 841}
 842
 843static int ifname_map_rev_lookup(struct dl *dl, const char *bus_name,
 844                                 const char *dev_name, uint32_t port_index,
 845                                 char **p_ifname)
 846{
 847        struct ifname_map *ifname_map;
 848
 849        list_for_each_entry(ifname_map, &dl->ifname_map_list, list) {
 850                if (strcmp(bus_name, ifname_map->bus_name) == 0 &&
 851                    strcmp(dev_name, ifname_map->dev_name) == 0 &&
 852                    port_index == ifname_map->port_index) {
 853                        *p_ifname = ifname_map->ifname;
 854                        return 0;
 855                }
 856        }
 857        return -ENOENT;
 858}
 859
 860static int strtouint64_t(const char *str, uint64_t *p_val)
 861{
 862        char *endptr;
 863        unsigned long long int val;
 864
 865        val = strtoull(str, &endptr, 10);
 866        if (endptr == str || *endptr != '\0')
 867                return -EINVAL;
 868        if (val > ULONG_MAX)
 869                return -ERANGE;
 870        *p_val = val;
 871        return 0;
 872}
 873
 874static int strtouint32_t(const char *str, uint32_t *p_val)
 875{
 876        char *endptr;
 877        unsigned long int val;
 878
 879        val = strtoul(str, &endptr, 10);
 880        if (endptr == str || *endptr != '\0')
 881                return -EINVAL;
 882        if (val > UINT_MAX)
 883                return -ERANGE;
 884        *p_val = val;
 885        return 0;
 886}
 887
 888static int strtouint16_t(const char *str, uint16_t *p_val)
 889{
 890        char *endptr;
 891        unsigned long int val;
 892
 893        val = strtoul(str, &endptr, 10);
 894        if (endptr == str || *endptr != '\0')
 895                return -EINVAL;
 896        if (val > USHRT_MAX)
 897                return -ERANGE;
 898        *p_val = val;
 899        return 0;
 900}
 901
 902static int strtouint8_t(const char *str, uint8_t *p_val)
 903{
 904        char *endptr;
 905        unsigned long int val;
 906
 907        val = strtoul(str, &endptr, 10);
 908        if (endptr == str || *endptr != '\0')
 909                return -EINVAL;
 910        if (val > UCHAR_MAX)
 911                return -ERANGE;
 912        *p_val = val;
 913        return 0;
 914}
 915
 916static int strtobool(const char *str, bool *p_val)
 917{
 918        bool val;
 919
 920        if (!strcmp(str, "true") || !strcmp(str, "1") ||
 921            !strcmp(str, "enable"))
 922                val = true;
 923        else if (!strcmp(str, "false") || !strcmp(str, "0") ||
 924                 !strcmp(str, "disable"))
 925                val = false;
 926        else
 927                return -EINVAL;
 928        *p_val = val;
 929        return 0;
 930}
 931
 932static int ident_str_validate(char *str, unsigned int expected)
 933{
 934        if (!str)
 935                return -EINVAL;
 936
 937        if (get_str_char_count(str, '/') != expected) {
 938                pr_err("Wrong identification string format.\n");
 939                return -EINVAL;
 940        }
 941
 942        return 0;
 943}
 944
 945static int __dl_argv_handle(char *str, char **p_bus_name, char **p_dev_name)
 946{
 947        int err;
 948
 949        err = str_split_by_char(str, p_bus_name, p_dev_name, '/');
 950        if (err) {
 951                pr_err("Devlink identification (\"bus_name/dev_name\") \"%s\" is invalid\n", str);
 952                return err;
 953        }
 954        return 0;
 955}
 956
 957static int dl_argv_handle(struct dl *dl, char **p_bus_name, char **p_dev_name)
 958{
 959        char *str = dl_argv_next(dl);
 960        int err;
 961
 962        err = ident_str_validate(str, 1);
 963        if (err) {
 964                pr_err("Devlink identification (\"bus_name/dev_name\") expected\n");
 965                return err;
 966        }
 967        return __dl_argv_handle(str, p_bus_name, p_dev_name);
 968}
 969
 970static int __dl_argv_handle_port(char *str,
 971                                 char **p_bus_name, char **p_dev_name,
 972                                 uint32_t *p_port_index)
 973{
 974        char *handlestr;
 975        char *portstr;
 976        int err;
 977
 978        err = str_split_by_char(str, &handlestr, &portstr, '/');
 979        if (err) {
 980                pr_err("Port identification \"%s\" is invalid\n", str);
 981                return err;
 982        }
 983        err = strtouint32_t(portstr, p_port_index);
 984        if (err) {
 985                pr_err("Port index \"%s\" is not a number or not within range\n",
 986                       portstr);
 987                return err;
 988        }
 989        err = str_split_by_char(handlestr, p_bus_name, p_dev_name, '/');
 990        if (err) {
 991                pr_err("Port identification \"%s\" is invalid\n", str);
 992                return err;
 993        }
 994        return 0;
 995}
 996
 997static int __dl_argv_handle_port_ifname(struct dl *dl, char *str,
 998                                        char **p_bus_name, char **p_dev_name,
 999                                        uint32_t *p_port_index)
1000{
1001        int err;
1002
1003        err = ifname_map_lookup(dl, str, p_bus_name, p_dev_name,
1004                                p_port_index);
1005        if (err) {
1006                pr_err("Netdevice \"%s\" not found\n", str);
1007                return err;
1008        }
1009        return 0;
1010}
1011
1012static int dl_argv_handle_port(struct dl *dl, char **p_bus_name,
1013                               char **p_dev_name, uint32_t *p_port_index)
1014{
1015        char *str = dl_argv_next(dl);
1016        unsigned int slash_count;
1017
1018        if (!str) {
1019                pr_err("Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\") expected.\n");
1020                return -EINVAL;
1021        }
1022        slash_count = get_str_char_count(str, '/');
1023        switch (slash_count) {
1024        case 0:
1025                return __dl_argv_handle_port_ifname(dl, str, p_bus_name,
1026                                                    p_dev_name, p_port_index);
1027        case 2:
1028                return __dl_argv_handle_port(str, p_bus_name,
1029                                             p_dev_name, p_port_index);
1030        default:
1031                pr_err("Wrong port identification string format.\n");
1032                pr_err("Expected \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
1033                return -EINVAL;
1034        }
1035}
1036
1037static int dl_argv_handle_both(struct dl *dl, char **p_bus_name,
1038                               char **p_dev_name, uint32_t *p_port_index,
1039                               uint64_t *p_handle_bit)
1040{
1041        char *str = dl_argv_next(dl);
1042        unsigned int slash_count;
1043        int err;
1044
1045        if (!str) {
1046                pr_err("One of following identifications expected:\n"
1047                       "Devlink identification (\"bus_name/dev_name\")\n"
1048                       "Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\")\n");
1049                return -EINVAL;
1050        }
1051        slash_count = get_str_char_count(str, '/');
1052        if (slash_count == 1) {
1053                err = __dl_argv_handle(str, p_bus_name, p_dev_name);
1054                if (err)
1055                        return err;
1056                *p_handle_bit = DL_OPT_HANDLE;
1057        } else if (slash_count == 2) {
1058                err = __dl_argv_handle_port(str, p_bus_name,
1059                                            p_dev_name, p_port_index);
1060                if (err)
1061                        return err;
1062                *p_handle_bit = DL_OPT_HANDLEP;
1063        } else if (slash_count == 0) {
1064                err = __dl_argv_handle_port_ifname(dl, str, p_bus_name,
1065                                                   p_dev_name, p_port_index);
1066                if (err)
1067                        return err;
1068                *p_handle_bit = DL_OPT_HANDLEP;
1069        } else {
1070                pr_err("Wrong port identification string format.\n");
1071                pr_err("Expected \"bus_name/dev_name\" or \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
1072                return -EINVAL;
1073        }
1074        return 0;
1075}
1076
1077static int __dl_argv_handle_name(char *str, char **p_bus_name,
1078                                 char **p_dev_name, char **p_name)
1079{
1080        char *handlestr;
1081        int err;
1082
1083        err = str_split_by_char(str, &handlestr, p_name, '/');
1084        if (err)
1085                return err;
1086
1087        return str_split_by_char(handlestr, p_bus_name, p_dev_name, '/');
1088}
1089
1090static int dl_argv_handle_region(struct dl *dl, char **p_bus_name,
1091                                 char **p_dev_name, char **p_region)
1092{
1093        char *str = dl_argv_next(dl);
1094        int err;
1095
1096        err = ident_str_validate(str, 2);
1097        if (err) {
1098                pr_err("Expected \"bus_name/dev_name/region\" identification.\n");
1099                return err;
1100        }
1101
1102        err = __dl_argv_handle_name(str, p_bus_name, p_dev_name, p_region);
1103        if (err)
1104                pr_err("Region identification \"%s\" is invalid\n", str);
1105        return err;
1106}
1107
1108
1109static int dl_argv_handle_rate_node(struct dl *dl, char **p_bus_name,
1110                                    char **p_dev_name, char **p_node)
1111{
1112        char *str = dl_argv_next(dl);
1113        int err;
1114
1115        err = ident_str_validate(str, 2);
1116        if (err) {
1117                pr_err("Expected \"bus_name/dev_name/node\" identification.\n");
1118                return err;
1119        }
1120
1121        err = __dl_argv_handle_name(str, p_bus_name, p_dev_name, p_node);
1122        if (err) {
1123                pr_err("Node identification \"%s\" is invalid\n", str);
1124                return err;
1125        }
1126
1127        if (!**p_node || strspn(*p_node, "0123456789") == strlen(*p_node)) {
1128                err = -EINVAL;
1129                pr_err("Node name cannot be a devlink port index or empty.\n");
1130        }
1131
1132        return err;
1133}
1134
1135static int dl_argv_handle_rate(struct dl *dl, char **p_bus_name,
1136                               char **p_dev_name, uint32_t *p_port_index,
1137                               char **p_node_name, uint64_t *p_handle_bit)
1138{
1139        char *str = dl_argv_next(dl);
1140        char *identifier;
1141        int err;
1142
1143        err = ident_str_validate(str, 2);
1144        if (err) {
1145                pr_err("Expected \"bus_name/dev_name/node\" or "
1146                       "\"bus_name/dev_name/port_index\" identification.\n");
1147                return err;
1148        }
1149
1150        err = __dl_argv_handle_name(str, p_bus_name, p_dev_name, &identifier);
1151        if (err) {
1152                pr_err("Identification \"%s\" is invalid\n", str);
1153                return err;
1154        }
1155
1156        if (!*identifier) {
1157                pr_err("Identifier cannot be empty");
1158                return -EINVAL;
1159        }
1160
1161        if (strspn(identifier, "0123456789") == strlen(identifier)) {
1162                err = strtouint32_t(identifier, p_port_index);
1163                if (err) {
1164                        pr_err("Port index \"%s\" is not a number"
1165                               " or not within range\n", identifier);
1166                        return err;
1167                }
1168                *p_handle_bit = DL_OPT_HANDLEP;
1169        } else {
1170                *p_handle_bit = DL_OPT_PORT_FN_RATE_NODE_NAME;
1171                *p_node_name = identifier;
1172        }
1173        return 0;
1174}
1175
1176static int dl_argv_uint64_t(struct dl *dl, uint64_t *p_val)
1177{
1178        char *str = dl_argv_next(dl);
1179        int err;
1180
1181        if (!str) {
1182                pr_err("Unsigned number argument expected\n");
1183                return -EINVAL;
1184        }
1185
1186        err = strtouint64_t(str, p_val);
1187        if (err) {
1188                pr_err("\"%s\" is not a number or not within range\n", str);
1189                return err;
1190        }
1191        return 0;
1192}
1193
1194static int dl_argv_uint32_t(struct dl *dl, uint32_t *p_val)
1195{
1196        char *str = dl_argv_next(dl);
1197        int err;
1198
1199        if (!str) {
1200                pr_err("Unsigned number argument expected\n");
1201                return -EINVAL;
1202        }
1203
1204        err = strtouint32_t(str, p_val);
1205        if (err) {
1206                pr_err("\"%s\" is not a number or not within range\n", str);
1207                return err;
1208        }
1209        return 0;
1210}
1211
1212static int dl_argv_uint16_t(struct dl *dl, uint16_t *p_val)
1213{
1214        char *str = dl_argv_next(dl);
1215        int err;
1216
1217        if (!str) {
1218                pr_err("Unsigned number argument expected\n");
1219                return -EINVAL;
1220        }
1221
1222        err = strtouint16_t(str, p_val);
1223        if (err) {
1224                pr_err("\"%s\" is not a number or not within range\n", str);
1225                return err;
1226        }
1227        return 0;
1228}
1229
1230static int dl_argv_bool(struct dl *dl, bool *p_val)
1231{
1232        char *str = dl_argv_next(dl);
1233        int err;
1234
1235        if (!str) {
1236                pr_err("Boolean argument expected\n");
1237                return -EINVAL;
1238        }
1239
1240        err = strtobool(str, p_val);
1241        if (err) {
1242                pr_err("\"%s\" is not a valid boolean value\n", str);
1243                return err;
1244        }
1245        return 0;
1246}
1247
1248static int dl_argv_str(struct dl *dl, const char **p_str)
1249{
1250        const char *str = dl_argv_next(dl);
1251
1252        if (!str) {
1253                pr_err("String parameter expected\n");
1254                return -EINVAL;
1255        }
1256        *p_str = str;
1257        return 0;
1258}
1259
1260static int port_type_get(const char *typestr, enum devlink_port_type *p_type)
1261{
1262        if (strcmp(typestr, "auto") == 0) {
1263                *p_type = DEVLINK_PORT_TYPE_AUTO;
1264        } else if (strcmp(typestr, "eth") == 0) {
1265                *p_type = DEVLINK_PORT_TYPE_ETH;
1266        } else if (strcmp(typestr, "ib") == 0) {
1267                *p_type = DEVLINK_PORT_TYPE_IB;
1268        } else {
1269                pr_err("Unknown port type \"%s\"\n", typestr);
1270                return -EINVAL;
1271        }
1272        return 0;
1273}
1274
1275static int pool_type_get(const char *typestr, enum devlink_sb_pool_type *p_type)
1276{
1277        if (strcmp(typestr, "ingress") == 0) {
1278                *p_type = DEVLINK_SB_POOL_TYPE_INGRESS;
1279        } else if (strcmp(typestr, "egress") == 0) {
1280                *p_type = DEVLINK_SB_POOL_TYPE_EGRESS;
1281        } else {
1282                pr_err("Unknown pool type \"%s\"\n", typestr);
1283                return -EINVAL;
1284        }
1285        return 0;
1286}
1287
1288static int threshold_type_get(const char *typestr,
1289                              enum devlink_sb_threshold_type *p_type)
1290{
1291        if (strcmp(typestr, "static") == 0) {
1292                *p_type = DEVLINK_SB_THRESHOLD_TYPE_STATIC;
1293        } else if (strcmp(typestr, "dynamic") == 0) {
1294                *p_type = DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC;
1295        } else {
1296                pr_err("Unknown threshold type \"%s\"\n", typestr);
1297                return -EINVAL;
1298        }
1299        return 0;
1300}
1301
1302static int eswitch_mode_get(const char *typestr,
1303                            enum devlink_eswitch_mode *p_mode)
1304{
1305        if (strcmp(typestr, ESWITCH_MODE_LEGACY) == 0) {
1306                *p_mode = DEVLINK_ESWITCH_MODE_LEGACY;
1307        } else if (strcmp(typestr, ESWITCH_MODE_SWITCHDEV) == 0) {
1308                *p_mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
1309        } else {
1310                pr_err("Unknown eswitch mode \"%s\"\n", typestr);
1311                return -EINVAL;
1312        }
1313        return 0;
1314}
1315
1316static int eswitch_inline_mode_get(const char *typestr,
1317                                   enum devlink_eswitch_inline_mode *p_mode)
1318{
1319        if (strcmp(typestr, ESWITCH_INLINE_MODE_NONE) == 0) {
1320                *p_mode = DEVLINK_ESWITCH_INLINE_MODE_NONE;
1321        } else if (strcmp(typestr, ESWITCH_INLINE_MODE_LINK) == 0) {
1322                *p_mode = DEVLINK_ESWITCH_INLINE_MODE_LINK;
1323        } else if (strcmp(typestr, ESWITCH_INLINE_MODE_NETWORK) == 0) {
1324                *p_mode = DEVLINK_ESWITCH_INLINE_MODE_NETWORK;
1325        } else if (strcmp(typestr, ESWITCH_INLINE_MODE_TRANSPORT) == 0) {
1326                *p_mode = DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT;
1327        } else {
1328                pr_err("Unknown eswitch inline mode \"%s\"\n", typestr);
1329                return -EINVAL;
1330        }
1331        return 0;
1332}
1333
1334static int
1335eswitch_encap_mode_get(const char *typestr,
1336                       enum devlink_eswitch_encap_mode *p_encap_mode)
1337{
1338        /* The initial implementation incorrectly accepted "enable"/"disable".
1339         * Carry it to maintain backward compatibility.
1340         */
1341        if (strcmp(typestr, "disable") == 0 ||
1342                   strcmp(typestr, ESWITCH_ENCAP_MODE_NONE) == 0) {
1343                *p_encap_mode = DEVLINK_ESWITCH_ENCAP_MODE_NONE;
1344        } else if (strcmp(typestr, "enable") == 0 ||
1345                   strcmp(typestr, ESWITCH_ENCAP_MODE_BASIC) == 0) {
1346                *p_encap_mode = DEVLINK_ESWITCH_ENCAP_MODE_BASIC;
1347        } else {
1348                pr_err("Unknown eswitch encap mode \"%s\"\n", typestr);
1349                return -EINVAL;
1350        }
1351        return 0;
1352}
1353
1354static int flash_overwrite_section_get(const char *sectionstr, uint32_t *mask)
1355{
1356        if (strcmp(sectionstr, "settings") == 0) {
1357                *mask |= DEVLINK_FLASH_OVERWRITE_SETTINGS;
1358        } else if (strcmp(sectionstr, "identifiers") == 0) {
1359                *mask |= DEVLINK_FLASH_OVERWRITE_IDENTIFIERS;
1360        } else {
1361                pr_err("Unknown overwrite section \"%s\"\n", sectionstr);
1362                return -EINVAL;
1363        }
1364        return 0;
1365}
1366
1367static int param_cmode_get(const char *cmodestr,
1368                           enum devlink_param_cmode *cmode)
1369{
1370        if (strcmp(cmodestr, PARAM_CMODE_RUNTIME_STR) == 0) {
1371                *cmode = DEVLINK_PARAM_CMODE_RUNTIME;
1372        } else if (strcmp(cmodestr, PARAM_CMODE_DRIVERINIT_STR) == 0) {
1373                *cmode = DEVLINK_PARAM_CMODE_DRIVERINIT;
1374        } else if (strcmp(cmodestr, PARAM_CMODE_PERMANENT_STR) == 0) {
1375                *cmode = DEVLINK_PARAM_CMODE_PERMANENT;
1376        } else {
1377                pr_err("Unknown configuration mode \"%s\"\n", cmodestr);
1378                return -EINVAL;
1379        }
1380        return 0;
1381}
1382
1383static int trap_action_get(const char *actionstr,
1384                           enum devlink_trap_action *p_action)
1385{
1386        if (strcmp(actionstr, "drop") == 0) {
1387                *p_action = DEVLINK_TRAP_ACTION_DROP;
1388        } else if (strcmp(actionstr, "trap") == 0) {
1389                *p_action = DEVLINK_TRAP_ACTION_TRAP;
1390        } else if (strcmp(actionstr, "mirror") == 0) {
1391                *p_action = DEVLINK_TRAP_ACTION_MIRROR;
1392        } else {
1393                pr_err("Unknown trap action \"%s\"\n", actionstr);
1394                return -EINVAL;
1395        }
1396        return 0;
1397}
1398
1399static int hw_addr_parse(const char *addrstr, char *hw_addr, uint32_t *len)
1400{
1401        int alen;
1402
1403        alen = ll_addr_a2n(hw_addr, MAX_ADDR_LEN, addrstr);
1404        if (alen < 0)
1405                return -EINVAL;
1406        *len = alen;
1407        return 0;
1408}
1409
1410static int reload_action_get(struct dl *dl, const char *actionstr,
1411                             enum devlink_reload_action *action)
1412{
1413        if (strcmp(actionstr, "driver_reinit") == 0) {
1414                *action = DEVLINK_RELOAD_ACTION_DRIVER_REINIT;
1415        } else if (strcmp(actionstr, "fw_activate") == 0) {
1416                *action = DEVLINK_RELOAD_ACTION_FW_ACTIVATE;
1417        } else {
1418                pr_err("Unknown reload action \"%s\"\n", actionstr);
1419                return -EINVAL;
1420        }
1421        return 0;
1422}
1423
1424static int reload_limit_get(struct dl *dl, const char *limitstr,
1425                             enum devlink_reload_limit *limit)
1426{
1427        if (strcmp(limitstr, "no_reset") == 0) {
1428                *limit = DEVLINK_RELOAD_LIMIT_NO_RESET;
1429        } else {
1430                pr_err("Unknown reload limit \"%s\"\n", limitstr);
1431                return -EINVAL;
1432        }
1433        return 0;
1434}
1435
1436static struct str_num_map port_flavour_map[] = {
1437        { .str = "physical", .num = DEVLINK_PORT_FLAVOUR_PHYSICAL },
1438        { .str = "cpu", .num = DEVLINK_PORT_FLAVOUR_CPU },
1439        { .str = "dsa", .num = DEVLINK_PORT_FLAVOUR_DSA },
1440        { .str = "pcipf", .num = DEVLINK_PORT_FLAVOUR_PCI_PF },
1441        { .str = "pcivf", .num = DEVLINK_PORT_FLAVOUR_PCI_VF },
1442        { .str = "pcisf", .num = DEVLINK_PORT_FLAVOUR_PCI_SF },
1443        { .str = "virtual", .num = DEVLINK_PORT_FLAVOUR_VIRTUAL},
1444        { .str = NULL, },
1445};
1446
1447static struct str_num_map port_fn_state_map[] = {
1448        { .str = "inactive", .num = DEVLINK_PORT_FN_STATE_INACTIVE},
1449        { .str = "active", .num = DEVLINK_PORT_FN_STATE_ACTIVE },
1450        { .str = NULL, }
1451};
1452
1453static struct str_num_map port_fn_opstate_map[] = {
1454        { .str = "attached", .num = DEVLINK_PORT_FN_OPSTATE_ATTACHED},
1455        { .str = "detached", .num = DEVLINK_PORT_FN_OPSTATE_DETACHED},
1456        { .str = NULL, }
1457};
1458
1459static int port_flavour_parse(const char *flavour, uint16_t *value)
1460{
1461        int num;
1462
1463        num = str_map_lookup_str(port_flavour_map, flavour);
1464        if (num < 0) {
1465                invarg("unknown flavour", flavour);
1466                return num;
1467        }
1468        *value = num;
1469        return 0;
1470}
1471
1472static int port_fn_state_parse(const char *statestr, uint8_t *state)
1473{
1474        int num;
1475
1476        num = str_map_lookup_str(port_fn_state_map, statestr);
1477        if (num < 0) {
1478                invarg("unknown state", statestr);
1479                return num;
1480        }
1481        *state = num;
1482        return 0;
1483}
1484
1485static int port_fn_rate_type_get(const char *typestr, uint16_t *type)
1486{
1487        if (!strcmp(typestr, "leaf"))
1488                *type = DEVLINK_RATE_TYPE_LEAF;
1489        else if (!strcmp(typestr, "node"))
1490                *type = DEVLINK_RATE_TYPE_NODE;
1491        else
1492                return -EINVAL;
1493        return 0;
1494}
1495
1496static int port_fn_rate_value_get(struct dl *dl, uint64_t *rate)
1497{
1498        const char *ratestr;
1499        __u64 rate64;
1500        int err;
1501
1502        err = dl_argv_str(dl, &ratestr);
1503        if (err)
1504                return err;
1505        err = get_rate64(&rate64, ratestr);
1506        if (err) {
1507                pr_err("Invalid rate value: \"%s\"\n", ratestr);
1508                return -EINVAL;
1509        }
1510
1511        *rate = rate64;
1512        return 0;
1513}
1514
1515struct dl_args_metadata {
1516        uint64_t o_flag;
1517        char err_msg[DL_ARGS_REQUIRED_MAX_ERR_LEN];
1518};
1519
1520static const struct dl_args_metadata dl_args_required[] = {
1521        {DL_OPT_PORT_TYPE,            "Port type not set."},
1522        {DL_OPT_PORT_COUNT,           "Port split count option expected."},
1523        {DL_OPT_SB_POOL,              "Pool index option expected."},
1524        {DL_OPT_SB_SIZE,              "Pool size option expected."},
1525        {DL_OPT_SB_TYPE,              "Pool type option expected."},
1526        {DL_OPT_SB_THTYPE,            "Pool threshold type option expected."},
1527        {DL_OPT_SB_TH,                "Threshold option expected."},
1528        {DL_OPT_SB_TC,                "TC index option expected."},
1529        {DL_OPT_ESWITCH_MODE,         "E-Switch mode option expected."},
1530        {DL_OPT_ESWITCH_INLINE_MODE,  "E-Switch inline-mode option expected."},
1531        {DL_OPT_DPIPE_TABLE_NAME,     "Dpipe table name expected."},
1532        {DL_OPT_DPIPE_TABLE_COUNTERS, "Dpipe table counter state expected."},
1533        {DL_OPT_ESWITCH_ENCAP_MODE,   "E-Switch encapsulation option expected."},
1534        {DL_OPT_RESOURCE_PATH,        "Resource path expected."},
1535        {DL_OPT_RESOURCE_SIZE,        "Resource size expected."},
1536        {DL_OPT_PARAM_NAME,           "Parameter name expected."},
1537        {DL_OPT_PARAM_VALUE,          "Value to set expected."},
1538        {DL_OPT_PARAM_CMODE,          "Configuration mode expected."},
1539        {DL_OPT_REGION_SNAPSHOT_ID,   "Region snapshot id expected."},
1540        {DL_OPT_REGION_ADDRESS,       "Region address value expected."},
1541        {DL_OPT_REGION_LENGTH,        "Region length value expected."},
1542        {DL_OPT_HEALTH_REPORTER_NAME, "Reporter's name is expected."},
1543        {DL_OPT_TRAP_NAME,            "Trap's name is expected."},
1544        {DL_OPT_TRAP_GROUP_NAME,      "Trap group's name is expected."},
1545        {DL_OPT_PORT_FUNCTION_HW_ADDR, "Port function's hardware address is expected."},
1546        {DL_OPT_PORT_FLAVOUR,          "Port flavour is expected."},
1547        {DL_OPT_PORT_PFNUMBER,         "Port PCI PF number is expected."},
1548};
1549
1550static int dl_args_finding_required_validate(uint64_t o_required,
1551                                             uint64_t o_found)
1552{
1553        uint64_t o_flag;
1554        int i;
1555
1556        for (i = 0; i < ARRAY_SIZE(dl_args_required); i++) {
1557                o_flag = dl_args_required[i].o_flag;
1558                if ((o_required & o_flag) && !(o_found & o_flag)) {
1559                        pr_err("%s\n", dl_args_required[i].err_msg);
1560                        return -EINVAL;
1561                }
1562        }
1563        if (o_required & ~o_found) {
1564                pr_err("BUG: unknown argument required but not found\n");
1565                return -EINVAL;
1566        }
1567        return 0;
1568}
1569
1570static int dl_argv_parse(struct dl *dl, uint64_t o_required,
1571                         uint64_t o_optional)
1572{
1573        struct dl_opts *opts = &dl->opts;
1574        uint64_t o_all = o_required | o_optional;
1575        uint64_t o_found = 0;
1576        int err;
1577
1578        if (o_required & DL_OPT_HANDLE && o_required & DL_OPT_HANDLEP) {
1579                uint64_t handle_bit;
1580
1581                err = dl_argv_handle_both(dl, &opts->bus_name, &opts->dev_name,
1582                                          &opts->port_index, &handle_bit);
1583                if (err)
1584                        return err;
1585                o_required &= ~(DL_OPT_HANDLE | DL_OPT_HANDLEP) | handle_bit;
1586                o_found |= handle_bit;
1587        } else if (o_required & DL_OPT_HANDLEP &&
1588                   o_required & DL_OPT_PORT_FN_RATE_NODE_NAME) {
1589                uint64_t handle_bit;
1590
1591                err = dl_argv_handle_rate(dl, &opts->bus_name, &opts->dev_name,
1592                                          &opts->port_index,
1593                                          &opts->rate_node_name,
1594                                          &handle_bit);
1595                if (err)
1596                        return err;
1597                o_required &= ~(DL_OPT_HANDLEP | DL_OPT_PORT_FN_RATE_NODE_NAME) |
1598                        handle_bit;
1599                o_found |= handle_bit;
1600        } else if (o_required & DL_OPT_HANDLE) {
1601                err = dl_argv_handle(dl, &opts->bus_name, &opts->dev_name);
1602                if (err)
1603                        return err;
1604                o_found |= DL_OPT_HANDLE;
1605        } else if (o_required & DL_OPT_HANDLEP) {
1606                err = dl_argv_handle_port(dl, &opts->bus_name, &opts->dev_name,
1607                                          &opts->port_index);
1608                if (err)
1609                        return err;
1610                o_found |= DL_OPT_HANDLEP;
1611        } else if (o_required & DL_OPT_HANDLE_REGION) {
1612                err = dl_argv_handle_region(dl, &opts->bus_name,
1613                                            &opts->dev_name,
1614                                            &opts->region_name);
1615                if (err)
1616                        return err;
1617                o_found |= DL_OPT_HANDLE_REGION;
1618        } else if (o_required & DL_OPT_PORT_FN_RATE_NODE_NAME) {
1619                err = dl_argv_handle_rate_node(dl, &opts->bus_name,
1620                                               &opts->dev_name,
1621                                               &opts->rate_node_name);
1622                if (err)
1623                        return err;
1624                o_found |= DL_OPT_PORT_FN_RATE_NODE_NAME;
1625        }
1626
1627        while (dl_argc(dl)) {
1628                if (dl_argv_match(dl, "type") &&
1629                    (o_all & DL_OPT_PORT_TYPE)) {
1630                        const char *typestr;
1631
1632                        dl_arg_inc(dl);
1633                        err = dl_argv_str(dl, &typestr);
1634                        if (err)
1635                                return err;
1636                        err = port_type_get(typestr, &opts->port_type);
1637                        if (err)
1638                                return err;
1639                        o_found |= DL_OPT_PORT_TYPE;
1640                } else if (dl_argv_match(dl, "count") &&
1641                           (o_all & DL_OPT_PORT_COUNT)) {
1642                        dl_arg_inc(dl);
1643                        err = dl_argv_uint32_t(dl, &opts->port_count);
1644                        if (err)
1645                                return err;
1646                        o_found |= DL_OPT_PORT_COUNT;
1647                } else if (dl_argv_match(dl, "sb") &&
1648                           (o_all & DL_OPT_SB)) {
1649                        dl_arg_inc(dl);
1650                        err = dl_argv_uint32_t(dl, &opts->sb_index);
1651                        if (err)
1652                                return err;
1653                        o_found |= DL_OPT_SB;
1654                } else if (dl_argv_match(dl, "pool") &&
1655                           (o_all & DL_OPT_SB_POOL)) {
1656                        dl_arg_inc(dl);
1657                        err = dl_argv_uint16_t(dl, &opts->sb_pool_index);
1658                        if (err)
1659                                return err;
1660                        o_found |= DL_OPT_SB_POOL;
1661                } else if (dl_argv_match(dl, "size") &&
1662                           (o_all & DL_OPT_SB_SIZE)) {
1663                        dl_arg_inc(dl);
1664                        err = dl_argv_uint32_t(dl, &opts->sb_pool_size);
1665                        if (err)
1666                                return err;
1667                        o_found |= DL_OPT_SB_SIZE;
1668                } else if (dl_argv_match(dl, "type") &&
1669                           (o_all & DL_OPT_SB_TYPE)) {
1670                        const char *typestr;
1671
1672                        dl_arg_inc(dl);
1673                        err = dl_argv_str(dl, &typestr);
1674                        if (err)
1675                                return err;
1676                        err = pool_type_get(typestr, &opts->sb_pool_type);
1677                        if (err)
1678                                return err;
1679                        o_found |= DL_OPT_SB_TYPE;
1680                } else if (dl_argv_match(dl, "thtype") &&
1681                           (o_all & DL_OPT_SB_THTYPE)) {
1682                        const char *typestr;
1683
1684                        dl_arg_inc(dl);
1685                        err = dl_argv_str(dl, &typestr);
1686                        if (err)
1687                                return err;
1688                        err = threshold_type_get(typestr,
1689                                                 &opts->sb_pool_thtype);
1690                        if (err)
1691                                return err;
1692                        o_found |= DL_OPT_SB_THTYPE;
1693                } else if (dl_argv_match(dl, "th") &&
1694                           (o_all & DL_OPT_SB_TH)) {
1695                        dl_arg_inc(dl);
1696                        err = dl_argv_uint32_t(dl, &opts->sb_threshold);
1697                        if (err)
1698                                return err;
1699                        o_found |= DL_OPT_SB_TH;
1700                } else if (dl_argv_match(dl, "tc") &&
1701                           (o_all & DL_OPT_SB_TC)) {
1702                        dl_arg_inc(dl);
1703                        err = dl_argv_uint16_t(dl, &opts->sb_tc_index);
1704                        if (err)
1705                                return err;
1706                        o_found |= DL_OPT_SB_TC;
1707                } else if (dl_argv_match(dl, "mode") &&
1708                           (o_all & DL_OPT_ESWITCH_MODE)) {
1709                        const char *typestr;
1710
1711                        dl_arg_inc(dl);
1712                        err = dl_argv_str(dl, &typestr);
1713                        if (err)
1714                                return err;
1715                        err = eswitch_mode_get(typestr, &opts->eswitch_mode);
1716                        if (err)
1717                                return err;
1718                        o_found |= DL_OPT_ESWITCH_MODE;
1719                } else if (dl_argv_match(dl, "inline-mode") &&
1720                           (o_all & DL_OPT_ESWITCH_INLINE_MODE)) {
1721                        const char *typestr;
1722
1723                        dl_arg_inc(dl);
1724                        err = dl_argv_str(dl, &typestr);
1725                        if (err)
1726                                return err;
1727                        err = eswitch_inline_mode_get(
1728                                typestr, &opts->eswitch_inline_mode);
1729                        if (err)
1730                                return err;
1731                        o_found |= DL_OPT_ESWITCH_INLINE_MODE;
1732                } else if (dl_argv_match(dl, "name") &&
1733                           (o_all & DL_OPT_DPIPE_TABLE_NAME)) {
1734                        dl_arg_inc(dl);
1735                        err = dl_argv_str(dl, &opts->dpipe_table_name);
1736                        if (err)
1737                                return err;
1738                        o_found |= DL_OPT_DPIPE_TABLE_NAME;
1739                } else if ((dl_argv_match(dl, "counters") ||
1740                            dl_argv_match(dl, "counters_enabled")) &&
1741                           (o_all & DL_OPT_DPIPE_TABLE_COUNTERS)) {
1742                        dl_arg_inc(dl);
1743                        err = dl_argv_bool(dl, &opts->dpipe_counters_enabled);
1744                        if (err)
1745                                return err;
1746                        o_found |= DL_OPT_DPIPE_TABLE_COUNTERS;
1747                } else if ((dl_argv_match(dl, "encap") || /* Original incorrect implementation */
1748                            dl_argv_match(dl, "encap-mode")) &&
1749                           (o_all & DL_OPT_ESWITCH_ENCAP_MODE)) {
1750                        const char *typestr;
1751
1752                        dl_arg_inc(dl);
1753                        err = dl_argv_str(dl, &typestr);
1754                        if (err)
1755                                return err;
1756                        err = eswitch_encap_mode_get(typestr,
1757                                                     &opts->eswitch_encap_mode);
1758                        if (err)
1759                                return err;
1760                        o_found |= DL_OPT_ESWITCH_ENCAP_MODE;
1761                } else if (dl_argv_match(dl, "path") &&
1762                           (o_all & DL_OPT_RESOURCE_PATH)) {
1763                        dl_arg_inc(dl);
1764                        err = dl_argv_str(dl, &opts->resource_path);
1765                        if (err)
1766                                return err;
1767                        o_found |= DL_OPT_RESOURCE_PATH;
1768                } else if (dl_argv_match(dl, "size") &&
1769                           (o_all & DL_OPT_RESOURCE_SIZE)) {
1770                        dl_arg_inc(dl);
1771                        err = dl_argv_uint64_t(dl, &opts->resource_size);
1772                        if (err)
1773                                return err;
1774                        o_found |= DL_OPT_RESOURCE_SIZE;
1775                } else if (dl_argv_match(dl, "name") &&
1776                           (o_all & DL_OPT_PARAM_NAME)) {
1777                        dl_arg_inc(dl);
1778                        err = dl_argv_str(dl, &opts->param_name);
1779                        if (err)
1780                                return err;
1781                        o_found |= DL_OPT_PARAM_NAME;
1782                } else if (dl_argv_match(dl, "value") &&
1783                           (o_all & DL_OPT_PARAM_VALUE)) {
1784                        dl_arg_inc(dl);
1785                        err = dl_argv_str(dl, &opts->param_value);
1786                        if (err)
1787                                return err;
1788                        o_found |= DL_OPT_PARAM_VALUE;
1789                } else if (dl_argv_match(dl, "cmode") &&
1790                           (o_all & DL_OPT_PARAM_CMODE)) {
1791                        const char *cmodestr;
1792
1793                        dl_arg_inc(dl);
1794                        err = dl_argv_str(dl, &cmodestr);
1795                        if (err)
1796                                return err;
1797                        err = param_cmode_get(cmodestr, &opts->cmode);
1798                        if (err)
1799                                return err;
1800                        o_found |= DL_OPT_PARAM_CMODE;
1801                } else if (dl_argv_match(dl, "snapshot") &&
1802                           (o_all & DL_OPT_REGION_SNAPSHOT_ID)) {
1803                        dl_arg_inc(dl);
1804                        err = dl_argv_uint32_t(dl, &opts->region_snapshot_id);
1805                        if (err)
1806                                return err;
1807                        o_found |= DL_OPT_REGION_SNAPSHOT_ID;
1808                } else if (dl_argv_match(dl, "address") &&
1809                           (o_all & DL_OPT_REGION_ADDRESS)) {
1810                        dl_arg_inc(dl);
1811                        err = dl_argv_uint64_t(dl, &opts->region_address);
1812                        if (err)
1813                                return err;
1814                        o_found |= DL_OPT_REGION_ADDRESS;
1815                } else if (dl_argv_match(dl, "length") &&
1816                           (o_all & DL_OPT_REGION_LENGTH)) {
1817                        dl_arg_inc(dl);
1818                        err = dl_argv_uint64_t(dl, &opts->region_length);
1819                        if (err)
1820                                return err;
1821                        o_found |= DL_OPT_REGION_LENGTH;
1822                } else if (dl_argv_match(dl, "file") &&
1823                           (o_all & DL_OPT_FLASH_FILE_NAME)) {
1824                        dl_arg_inc(dl);
1825                        err = dl_argv_str(dl, &opts->flash_file_name);
1826                        if (err)
1827                                return err;
1828                        o_found |= DL_OPT_FLASH_FILE_NAME;
1829                } else if (dl_argv_match(dl, "component") &&
1830                           (o_all & DL_OPT_FLASH_COMPONENT)) {
1831                        dl_arg_inc(dl);
1832                        err = dl_argv_str(dl, &opts->flash_component);
1833                        if (err)
1834                                return err;
1835                        o_found |= DL_OPT_FLASH_COMPONENT;
1836
1837                } else if (dl_argv_match(dl, "overwrite") &&
1838                                (o_all & DL_OPT_FLASH_OVERWRITE)) {
1839                        const char *sectionstr;
1840
1841                        dl_arg_inc(dl);
1842                        err = dl_argv_str(dl, &sectionstr);
1843                        if(err)
1844                                return err;
1845                        err = flash_overwrite_section_get(sectionstr,
1846                                                          &opts->overwrite_mask);
1847                        if (err)
1848                                return err;
1849                        o_found |= DL_OPT_FLASH_OVERWRITE;
1850
1851                } else if (dl_argv_match(dl, "reporter") &&
1852                           (o_all & DL_OPT_HEALTH_REPORTER_NAME)) {
1853                        dl_arg_inc(dl);
1854                        err = dl_argv_str(dl, &opts->reporter_name);
1855                        if (err)
1856                                return err;
1857                        o_found |= DL_OPT_HEALTH_REPORTER_NAME;
1858                } else if (dl_argv_match(dl, "grace_period") &&
1859                           (o_all & DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD)) {
1860                        dl_arg_inc(dl);
1861                        err = dl_argv_uint64_t(dl,
1862                                               &opts->reporter_graceful_period);
1863                        if (err)
1864                                return err;
1865                        o_found |= DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD;
1866                } else if (dl_argv_match(dl, "auto_recover") &&
1867                        (o_all & DL_OPT_HEALTH_REPORTER_AUTO_RECOVER)) {
1868                        dl_arg_inc(dl);
1869                        err = dl_argv_bool(dl, &opts->reporter_auto_recover);
1870                        if (err)
1871                                return err;
1872                        o_found |= DL_OPT_HEALTH_REPORTER_AUTO_RECOVER;
1873                } else if (dl_argv_match(dl, "auto_dump") &&
1874                        (o_all & DL_OPT_HEALTH_REPORTER_AUTO_DUMP)) {
1875                        dl_arg_inc(dl);
1876                        err = dl_argv_bool(dl, &opts->reporter_auto_dump);
1877                        if (err)
1878                                return err;
1879                        o_found |= DL_OPT_HEALTH_REPORTER_AUTO_DUMP;
1880                } else if (dl_argv_match(dl, "trap") &&
1881                           (o_all & DL_OPT_TRAP_NAME)) {
1882                        dl_arg_inc(dl);
1883                        err = dl_argv_str(dl, &opts->trap_name);
1884                        if (err)
1885                                return err;
1886                        o_found |= DL_OPT_TRAP_NAME;
1887                } else if (dl_argv_match(dl, "group") &&
1888                           (o_all & DL_OPT_TRAP_GROUP_NAME)) {
1889                        dl_arg_inc(dl);
1890                        err = dl_argv_str(dl, &opts->trap_group_name);
1891                        if (err)
1892                                return err;
1893                        o_found |= DL_OPT_TRAP_GROUP_NAME;
1894                } else if (dl_argv_match(dl, "action") &&
1895                           (o_all & DL_OPT_TRAP_ACTION)) {
1896                        const char *actionstr;
1897
1898                        dl_arg_inc(dl);
1899                        err = dl_argv_str(dl, &actionstr);
1900                        if (err)
1901                                return err;
1902                        err = trap_action_get(actionstr, &opts->trap_action);
1903                        if (err)
1904                                return err;
1905                        o_found |= DL_OPT_TRAP_ACTION;
1906                } else if (dl_argv_match(dl, "netns") &&
1907                        (o_all & DL_OPT_NETNS)) {
1908                        const char *netns_str;
1909
1910                        dl_arg_inc(dl);
1911                        err = dl_argv_str(dl, &netns_str);
1912                        if (err)
1913                                return err;
1914                        opts->netns = netns_get_fd(netns_str);
1915                        if ((int)opts->netns < 0) {
1916                                dl_arg_dec(dl);
1917                                err = dl_argv_uint32_t(dl, &opts->netns);
1918                                if (err)
1919                                        return err;
1920                                opts->netns_is_pid = true;
1921                        }
1922                        o_found |= DL_OPT_NETNS;
1923                } else if (dl_argv_match(dl, "action") &&
1924                           (o_all & DL_OPT_RELOAD_ACTION)) {
1925                        const char *actionstr;
1926
1927                        dl_arg_inc(dl);
1928                        err = dl_argv_str(dl, &actionstr);
1929                        if (err)
1930                                return err;
1931                        err = reload_action_get(dl, actionstr, &opts->reload_action);
1932                        if (err)
1933                                return err;
1934                        o_found |= DL_OPT_RELOAD_ACTION;
1935                } else if (dl_argv_match(dl, "limit") &&
1936                           (o_all & DL_OPT_RELOAD_LIMIT)) {
1937                        const char *limitstr;
1938
1939                        dl_arg_inc(dl);
1940                        err = dl_argv_str(dl, &limitstr);
1941                        if (err)
1942                                return err;
1943                        err = reload_limit_get(dl, limitstr, &opts->reload_limit);
1944                        if (err)
1945                                return err;
1946                        o_found |= DL_OPT_RELOAD_LIMIT;
1947                } else if (dl_argv_match(dl, "policer") &&
1948                           (o_all & DL_OPT_TRAP_POLICER_ID)) {
1949                        dl_arg_inc(dl);
1950                        err = dl_argv_uint32_t(dl, &opts->trap_policer_id);
1951                        if (err)
1952                                return err;
1953                        o_found |= DL_OPT_TRAP_POLICER_ID;
1954                } else if (dl_argv_match(dl, "nopolicer") &&
1955                           (o_all & DL_OPT_TRAP_POLICER_ID)) {
1956                        dl_arg_inc(dl);
1957                        opts->trap_policer_id = 0;
1958                        o_found |= DL_OPT_TRAP_POLICER_ID;
1959                } else if (dl_argv_match(dl, "rate") &&
1960                           (o_all & DL_OPT_TRAP_POLICER_RATE)) {
1961                        dl_arg_inc(dl);
1962                        err = dl_argv_uint64_t(dl, &opts->trap_policer_rate);
1963                        if (err)
1964                                return err;
1965                        o_found |= DL_OPT_TRAP_POLICER_RATE;
1966                } else if (dl_argv_match(dl, "burst") &&
1967                           (o_all & DL_OPT_TRAP_POLICER_BURST)) {
1968                        dl_arg_inc(dl);
1969                        err = dl_argv_uint64_t(dl, &opts->trap_policer_burst);
1970                        if (err)
1971                                return err;
1972                        o_found |= DL_OPT_TRAP_POLICER_BURST;
1973                } else if (dl_argv_match(dl, "hw_addr") &&
1974                           (o_all & DL_OPT_PORT_FUNCTION_HW_ADDR)) {
1975                        const char *addrstr;
1976
1977                        dl_arg_inc(dl);
1978                        err = dl_argv_str(dl, &addrstr);
1979                        if (err)
1980                                return err;
1981                        err = hw_addr_parse(addrstr, opts->port_function_hw_addr,
1982                                            &opts->port_function_hw_addr_len);
1983                        if (err)
1984                                return err;
1985                        o_found |= DL_OPT_PORT_FUNCTION_HW_ADDR;
1986                } else if (dl_argv_match(dl, "state") &&
1987                           (o_all & DL_OPT_PORT_FUNCTION_STATE)) {
1988                        const char *statestr;
1989
1990                        dl_arg_inc(dl);
1991                        err = dl_argv_str(dl, &statestr);
1992                        if (err)
1993                                return err;
1994                        err = port_fn_state_parse(statestr, &opts->port_fn_state);
1995                        if (err)
1996                                return err;
1997
1998                        o_found |= DL_OPT_PORT_FUNCTION_STATE;
1999                } else if (dl_argv_match(dl, "flavour") && (o_all & DL_OPT_PORT_FLAVOUR)) {
2000                        const char *flavourstr;
2001
2002                        dl_arg_inc(dl);
2003                        err = dl_argv_str(dl, &flavourstr);
2004                        if (err)
2005                                return err;
2006                        err = port_flavour_parse(flavourstr, &opts->port_flavour);
2007                        if (err)
2008                                return err;
2009                        o_found |= DL_OPT_PORT_FLAVOUR;
2010                } else if (dl_argv_match(dl, "pfnum") && (o_all & DL_OPT_PORT_PFNUMBER)) {
2011                        dl_arg_inc(dl);
2012                        err = dl_argv_uint16_t(dl, &opts->port_pfnumber);
2013                        if (err)
2014                                return err;
2015                        o_found |= DL_OPT_PORT_PFNUMBER;
2016                } else if (dl_argv_match(dl, "sfnum") && (o_all & DL_OPT_PORT_SFNUMBER)) {
2017                        dl_arg_inc(dl);
2018                        err = dl_argv_uint32_t(dl, &opts->port_sfnumber);
2019                        if (err)
2020                                return err;
2021                        o_found |= DL_OPT_PORT_SFNUMBER;
2022                } else if (dl_argv_match(dl, "controller") && (o_all & DL_OPT_PORT_CONTROLLER)) {
2023                        dl_arg_inc(dl);
2024                        err = dl_argv_uint32_t(dl, &opts->port_controller);
2025                        if (err)
2026                                return err;
2027                        o_found |= DL_OPT_PORT_CONTROLLER;
2028                } else if (dl_argv_match(dl, "type") &&
2029                           (o_all & DL_OPT_PORT_FN_RATE_TYPE)) {
2030                        const char *typestr;
2031
2032                        dl_arg_inc(dl);
2033                        err = dl_argv_str(dl, &typestr);
2034                        if (err)
2035                                return err;
2036                        err = port_fn_rate_type_get(typestr, &opts->rate_type);
2037                        if (err)
2038                                return err;
2039                        o_found |= DL_OPT_PORT_FN_RATE_TYPE;
2040                } else if (dl_argv_match(dl, "tx_share") &&
2041                           (o_all & DL_OPT_PORT_FN_RATE_TX_SHARE)) {
2042                        dl_arg_inc(dl);
2043                        err = port_fn_rate_value_get(dl, &opts->rate_tx_share);
2044                        if (err)
2045                                return err;
2046                        o_found |= DL_OPT_PORT_FN_RATE_TX_SHARE;
2047                } else if (dl_argv_match(dl, "tx_max") &&
2048                           (o_all & DL_OPT_PORT_FN_RATE_TX_MAX)) {
2049                        dl_arg_inc(dl);
2050                        err = port_fn_rate_value_get(dl, &opts->rate_tx_max);
2051                        if (err)
2052                                return err;
2053                        o_found |= DL_OPT_PORT_FN_RATE_TX_MAX;
2054                } else if (dl_argv_match(dl, "parent") &&
2055                           (o_all & DL_OPT_PORT_FN_RATE_PARENT)) {
2056                        dl_arg_inc(dl);
2057                        err = dl_argv_str(dl, &opts->rate_parent_node);
2058                        if (err)
2059                                return err;
2060                        o_found |= DL_OPT_PORT_FN_RATE_PARENT;
2061                } else if (dl_argv_match(dl, "noparent") &&
2062                           (o_all & DL_OPT_PORT_FN_RATE_PARENT)) {
2063                        dl_arg_inc(dl);
2064                        opts->rate_parent_node = "";
2065                        o_found |= DL_OPT_PORT_FN_RATE_PARENT;
2066                } else {
2067                        pr_err("Unknown option \"%s\"\n", dl_argv(dl));
2068                        return -EINVAL;
2069                }
2070        }
2071
2072        opts->present = o_found;
2073
2074        if ((o_optional & DL_OPT_SB) && !(o_found & DL_OPT_SB)) {
2075                opts->sb_index = 0;
2076                opts->present |= DL_OPT_SB;
2077        }
2078
2079        return dl_args_finding_required_validate(o_required, o_found);
2080}
2081
2082static void
2083dl_function_attr_put(struct nlmsghdr *nlh, const struct dl_opts *opts)
2084{
2085        struct nlattr *nest;
2086
2087        nest = mnl_attr_nest_start(nlh, DEVLINK_ATTR_PORT_FUNCTION);
2088
2089        if (opts->present & DL_OPT_PORT_FUNCTION_HW_ADDR)
2090                mnl_attr_put(nlh, DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR,
2091                             opts->port_function_hw_addr_len,
2092                             opts->port_function_hw_addr);
2093        if (opts->present & DL_OPT_PORT_FUNCTION_STATE)
2094                mnl_attr_put_u8(nlh, DEVLINK_PORT_FN_ATTR_STATE,
2095                                opts->port_fn_state);
2096        mnl_attr_nest_end(nlh, nest);
2097}
2098
2099static void
2100dl_flash_update_overwrite_put(struct nlmsghdr *nlh, const struct dl_opts *opts)
2101{
2102        struct nla_bitfield32 overwrite_mask;
2103
2104        overwrite_mask.selector = DEVLINK_SUPPORTED_FLASH_OVERWRITE_SECTIONS;
2105        overwrite_mask.value = opts->overwrite_mask;
2106
2107        mnl_attr_put(nlh, DEVLINK_ATTR_FLASH_UPDATE_OVERWRITE_MASK,
2108                     sizeof(overwrite_mask), &overwrite_mask);
2109}
2110
2111static void
2112dl_reload_limits_put(struct nlmsghdr *nlh, const struct dl_opts *opts)
2113{
2114        struct nla_bitfield32 limits;
2115
2116        limits.selector = DEVLINK_RELOAD_LIMITS_VALID_MASK;
2117        limits.value = BIT(opts->reload_limit);
2118        mnl_attr_put(nlh, DEVLINK_ATTR_RELOAD_LIMITS, sizeof(limits), &limits);
2119}
2120
2121static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl)
2122{
2123        struct dl_opts *opts = &dl->opts;
2124
2125        if (opts->present & DL_OPT_HANDLE) {
2126                mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, opts->bus_name);
2127                mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, opts->dev_name);
2128        } else if (opts->present & DL_OPT_HANDLEP) {
2129                mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, opts->bus_name);
2130                mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, opts->dev_name);
2131                mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX,
2132                                 opts->port_index);
2133        } else if (opts->present & DL_OPT_HANDLE_REGION) {
2134                mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, opts->bus_name);
2135                mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, opts->dev_name);
2136                mnl_attr_put_strz(nlh, DEVLINK_ATTR_REGION_NAME,
2137                                  opts->region_name);
2138        } else if (opts->present & DL_OPT_PORT_FN_RATE_NODE_NAME) {
2139                mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, opts->bus_name);
2140                mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, opts->dev_name);
2141                mnl_attr_put_strz(nlh, DEVLINK_ATTR_RATE_NODE_NAME,
2142                                  opts->rate_node_name);
2143        }
2144        if (opts->present & DL_OPT_PORT_TYPE)
2145                mnl_attr_put_u16(nlh, DEVLINK_ATTR_PORT_TYPE,
2146                                 opts->port_type);
2147        if (opts->present & DL_OPT_PORT_COUNT)
2148                mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_SPLIT_COUNT,
2149                                 opts->port_count);
2150        if (opts->present & DL_OPT_SB)
2151                mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX,
2152                                 opts->sb_index);
2153        if (opts->present & DL_OPT_SB_POOL)
2154                mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX,
2155                                 opts->sb_pool_index);
2156        if (opts->present & DL_OPT_SB_SIZE)
2157                mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_POOL_SIZE,
2158                                 opts->sb_pool_size);
2159        if (opts->present & DL_OPT_SB_TYPE)
2160                mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_TYPE,
2161                                opts->sb_pool_type);
2162        if (opts->present & DL_OPT_SB_THTYPE)
2163                mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE,
2164                                opts->sb_pool_thtype);
2165        if (opts->present & DL_OPT_SB_TH)
2166                mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_THRESHOLD,
2167                                 opts->sb_threshold);
2168        if (opts->present & DL_OPT_SB_TC)
2169                mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_TC_INDEX,
2170                                 opts->sb_tc_index);
2171        if (opts->present & DL_OPT_ESWITCH_MODE)
2172                mnl_attr_put_u16(nlh, DEVLINK_ATTR_ESWITCH_MODE,
2173                                 opts->eswitch_mode);
2174        if (opts->present & DL_OPT_ESWITCH_INLINE_MODE)
2175                mnl_attr_put_u8(nlh, DEVLINK_ATTR_ESWITCH_INLINE_MODE,
2176                                opts->eswitch_inline_mode);
2177        if (opts->present & DL_OPT_DPIPE_TABLE_NAME)
2178                mnl_attr_put_strz(nlh, DEVLINK_ATTR_DPIPE_TABLE_NAME,
2179                                  opts->dpipe_table_name);
2180        if (opts->present & DL_OPT_DPIPE_TABLE_COUNTERS)
2181                mnl_attr_put_u8(nlh, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED,
2182                                opts->dpipe_counters_enabled);
2183        if (opts->present & DL_OPT_ESWITCH_ENCAP_MODE)
2184                mnl_attr_put_u8(nlh, DEVLINK_ATTR_ESWITCH_ENCAP_MODE,
2185                                opts->eswitch_encap_mode);
2186        if ((opts->present & DL_OPT_RESOURCE_PATH) && opts->resource_id_valid)
2187                mnl_attr_put_u64(nlh, DEVLINK_ATTR_RESOURCE_ID,
2188                                 opts->resource_id);
2189        if (opts->present & DL_OPT_RESOURCE_SIZE)
2190                mnl_attr_put_u64(nlh, DEVLINK_ATTR_RESOURCE_SIZE,
2191                                 opts->resource_size);
2192        if (opts->present & DL_OPT_PARAM_NAME)
2193                mnl_attr_put_strz(nlh, DEVLINK_ATTR_PARAM_NAME,
2194                                  opts->param_name);
2195        if (opts->present & DL_OPT_PARAM_CMODE)
2196                mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_VALUE_CMODE,
2197                                opts->cmode);
2198        if (opts->present & DL_OPT_REGION_SNAPSHOT_ID)
2199                mnl_attr_put_u32(nlh, DEVLINK_ATTR_REGION_SNAPSHOT_ID,
2200                                 opts->region_snapshot_id);
2201        if (opts->present & DL_OPT_REGION_ADDRESS)
2202                mnl_attr_put_u64(nlh, DEVLINK_ATTR_REGION_CHUNK_ADDR,
2203                                 opts->region_address);
2204        if (opts->present & DL_OPT_REGION_LENGTH)
2205                mnl_attr_put_u64(nlh, DEVLINK_ATTR_REGION_CHUNK_LEN,
2206                                 opts->region_length);
2207        if (opts->present & DL_OPT_FLASH_FILE_NAME)
2208                mnl_attr_put_strz(nlh, DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME,
2209                                  opts->flash_file_name);
2210        if (opts->present & DL_OPT_FLASH_COMPONENT)
2211                mnl_attr_put_strz(nlh, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT,
2212                                  opts->flash_component);
2213        if (opts->present & DL_OPT_FLASH_OVERWRITE)
2214                dl_flash_update_overwrite_put(nlh, opts);
2215        if (opts->present & DL_OPT_HEALTH_REPORTER_NAME)
2216                mnl_attr_put_strz(nlh, DEVLINK_ATTR_HEALTH_REPORTER_NAME,
2217                                  opts->reporter_name);
2218        if (opts->present & DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD)
2219                mnl_attr_put_u64(nlh,
2220                                 DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
2221                                 opts->reporter_graceful_period);
2222        if (opts->present & DL_OPT_HEALTH_REPORTER_AUTO_RECOVER)
2223                mnl_attr_put_u8(nlh, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER,
2224                                opts->reporter_auto_recover);
2225        if (opts->present & DL_OPT_HEALTH_REPORTER_AUTO_DUMP)
2226                mnl_attr_put_u8(nlh, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP,
2227                                opts->reporter_auto_dump);
2228        if (opts->present & DL_OPT_TRAP_NAME)
2229                mnl_attr_put_strz(nlh, DEVLINK_ATTR_TRAP_NAME,
2230                                  opts->trap_name);
2231        if (opts->present & DL_OPT_TRAP_GROUP_NAME)
2232                mnl_attr_put_strz(nlh, DEVLINK_ATTR_TRAP_GROUP_NAME,
2233                                  opts->trap_group_name);
2234        if (opts->present & DL_OPT_TRAP_ACTION)
2235                mnl_attr_put_u8(nlh, DEVLINK_ATTR_TRAP_ACTION,
2236                                opts->trap_action);
2237        if (opts->present & DL_OPT_NETNS)
2238                mnl_attr_put_u32(nlh,
2239                                 opts->netns_is_pid ? DEVLINK_ATTR_NETNS_PID :
2240                                                      DEVLINK_ATTR_NETNS_FD,
2241                                 opts->netns);
2242        if (opts->present & DL_OPT_RELOAD_ACTION)
2243                mnl_attr_put_u8(nlh, DEVLINK_ATTR_RELOAD_ACTION,
2244                                opts->reload_action);
2245        if (opts->present & DL_OPT_RELOAD_LIMIT)
2246                dl_reload_limits_put(nlh, opts);
2247        if (opts->present & DL_OPT_TRAP_POLICER_ID)
2248                mnl_attr_put_u32(nlh, DEVLINK_ATTR_TRAP_POLICER_ID,
2249                                 opts->trap_policer_id);
2250        if (opts->present & DL_OPT_TRAP_POLICER_RATE)
2251                mnl_attr_put_u64(nlh, DEVLINK_ATTR_TRAP_POLICER_RATE,
2252                                 opts->trap_policer_rate);
2253        if (opts->present & DL_OPT_TRAP_POLICER_BURST)
2254                mnl_attr_put_u64(nlh, DEVLINK_ATTR_TRAP_POLICER_BURST,
2255                                 opts->trap_policer_burst);
2256        if (opts->present & (DL_OPT_PORT_FUNCTION_HW_ADDR | DL_OPT_PORT_FUNCTION_STATE))
2257                dl_function_attr_put(nlh, opts);
2258        if (opts->present & DL_OPT_PORT_FLAVOUR)
2259                mnl_attr_put_u16(nlh, DEVLINK_ATTR_PORT_FLAVOUR, opts->port_flavour);
2260        if (opts->present & DL_OPT_PORT_PFNUMBER)
2261                mnl_attr_put_u16(nlh, DEVLINK_ATTR_PORT_PCI_PF_NUMBER, opts->port_pfnumber);
2262        if (opts->present & DL_OPT_PORT_SFNUMBER)
2263                mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_PCI_SF_NUMBER, opts->port_sfnumber);
2264        if (opts->present & DL_OPT_PORT_CONTROLLER)
2265                mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_CONTROLLER_NUMBER,
2266                                 opts->port_controller);
2267        if (opts->present & DL_OPT_PORT_FN_RATE_TYPE)
2268                mnl_attr_put_u16(nlh, DEVLINK_ATTR_RATE_TYPE,
2269                                 opts->rate_type);
2270        if (opts->present & DL_OPT_PORT_FN_RATE_TX_SHARE)
2271                mnl_attr_put_u64(nlh, DEVLINK_ATTR_RATE_TX_SHARE,
2272                                 opts->rate_tx_share);
2273        if (opts->present & DL_OPT_PORT_FN_RATE_TX_MAX)
2274                mnl_attr_put_u64(nlh, DEVLINK_ATTR_RATE_TX_MAX,
2275                                 opts->rate_tx_max);
2276        if (opts->present & DL_OPT_PORT_FN_RATE_PARENT)
2277                mnl_attr_put_strz(nlh, DEVLINK_ATTR_RATE_PARENT_NODE_NAME,
2278                                  opts->rate_parent_node);
2279}
2280
2281static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl,
2282                             uint64_t o_required, uint64_t o_optional)
2283{
2284        int err;
2285
2286        err = dl_argv_parse(dl, o_required, o_optional);
2287        if (err)
2288                return err;
2289        dl_opts_put(nlh, dl);
2290        return 0;
2291}
2292
2293static bool dl_dump_filter(struct dl *dl, struct nlattr **tb)
2294{
2295        struct dl_opts *opts = &dl->opts;
2296        struct nlattr *attr_bus_name = tb[DEVLINK_ATTR_BUS_NAME];
2297        struct nlattr *attr_dev_name = tb[DEVLINK_ATTR_DEV_NAME];
2298        struct nlattr *attr_port_index = tb[DEVLINK_ATTR_PORT_INDEX];
2299        struct nlattr *attr_sb_index = tb[DEVLINK_ATTR_SB_INDEX];
2300
2301        if (opts->present & DL_OPT_HANDLE &&
2302            attr_bus_name && attr_dev_name) {
2303                const char *bus_name = mnl_attr_get_str(attr_bus_name);
2304                const char *dev_name = mnl_attr_get_str(attr_dev_name);
2305
2306                if (strcmp(bus_name, opts->bus_name) != 0 ||
2307                    strcmp(dev_name, opts->dev_name) != 0)
2308                        return false;
2309        }
2310        if (opts->present & DL_OPT_HANDLEP &&
2311            attr_bus_name && attr_dev_name && attr_port_index) {
2312                const char *bus_name = mnl_attr_get_str(attr_bus_name);
2313                const char *dev_name = mnl_attr_get_str(attr_dev_name);
2314                uint32_t port_index = mnl_attr_get_u32(attr_port_index);
2315
2316                if (strcmp(bus_name, opts->bus_name) != 0 ||
2317                    strcmp(dev_name, opts->dev_name) != 0 ||
2318                    port_index != opts->port_index)
2319                        return false;
2320        }
2321        if (opts->present & DL_OPT_SB && attr_sb_index) {
2322                uint32_t sb_index = mnl_attr_get_u32(attr_sb_index);
2323
2324                if (sb_index != opts->sb_index)
2325                        return false;
2326        }
2327        return true;
2328}
2329
2330static void cmd_dev_help(void)
2331{
2332        pr_err("Usage: devlink dev show [ DEV ]\n");
2333        pr_err("       devlink dev eswitch set DEV [ mode { legacy | switchdev } ]\n");
2334        pr_err("                               [ inline-mode { none | link | network | transport } ]\n");
2335        pr_err("                               [ encap-mode { none | basic } ]\n");
2336        pr_err("       devlink dev eswitch show DEV\n");
2337        pr_err("       devlink dev param set DEV name PARAMETER value VALUE cmode { permanent | driverinit | runtime }\n");
2338        pr_err("       devlink dev param show [DEV name PARAMETER]\n");
2339        pr_err("       devlink dev reload DEV [ netns { PID | NAME | ID } ]\n");
2340        pr_err("                              [ action { driver_reinit | fw_activate } ] [ limit no_reset ]\n");
2341        pr_err("       devlink dev info [ DEV ]\n");
2342        pr_err("       devlink dev flash DEV file PATH [ component NAME ] [ overwrite SECTION ]\n");
2343}
2344
2345static bool cmp_arr_last_handle(struct dl *dl, const char *bus_name,
2346                                const char *dev_name)
2347{
2348        if (!dl->arr_last.present)
2349                return false;
2350        return strcmp(dl->arr_last.bus_name, bus_name) == 0 &&
2351               strcmp(dl->arr_last.dev_name, dev_name) == 0;
2352}
2353
2354static void arr_last_handle_set(struct dl *dl, const char *bus_name,
2355                                const char *dev_name)
2356{
2357        dl->arr_last.present = true;
2358        free(dl->arr_last.dev_name);
2359        free(dl->arr_last.bus_name);
2360        dl->arr_last.bus_name = strdup(bus_name);
2361        dl->arr_last.dev_name = strdup(dev_name);
2362}
2363
2364static bool should_arr_last_handle_start(struct dl *dl, const char *bus_name,
2365                                         const char *dev_name)
2366{
2367        return !cmp_arr_last_handle(dl, bus_name, dev_name);
2368}
2369
2370static bool should_arr_last_handle_end(struct dl *dl, const char *bus_name,
2371                                       const char *dev_name)
2372{
2373        return dl->arr_last.present &&
2374               !cmp_arr_last_handle(dl, bus_name, dev_name);
2375}
2376
2377static void __pr_out_handle_start(struct dl *dl, struct nlattr **tb,
2378                                  bool content, bool array)
2379{
2380        const char *bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
2381        const char *dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
2382        char buf[64];
2383
2384        sprintf(buf, "%s/%s", bus_name, dev_name);
2385
2386        if (dl->json_output) {
2387                if (array) {
2388                        if (should_arr_last_handle_end(dl, bus_name, dev_name))
2389                                close_json_array(PRINT_JSON, NULL);
2390                        if (should_arr_last_handle_start(dl, bus_name,
2391                                                         dev_name)) {
2392                                open_json_array(PRINT_JSON, buf);
2393                                open_json_object(NULL);
2394                                arr_last_handle_set(dl, bus_name, dev_name);
2395                        } else {
2396                                open_json_object(NULL);
2397                        }
2398                } else {
2399                        open_json_object(buf);
2400                }
2401        } else {
2402                if (array) {
2403                        if (should_arr_last_handle_end(dl, bus_name, dev_name))
2404                                __pr_out_indent_dec();
2405                        if (should_arr_last_handle_start(dl, bus_name,
2406                                                         dev_name)) {
2407                                pr_out("%s%s", buf, content ? ":" : "");
2408                                __pr_out_newline();
2409                                __pr_out_indent_inc();
2410                                arr_last_handle_set(dl, bus_name, dev_name);
2411                        }
2412                } else {
2413                        pr_out("%s%s", buf, content ? ":" : "");
2414                }
2415        }
2416}
2417
2418static void pr_out_handle_start_arr(struct dl *dl, struct nlattr **tb)
2419{
2420        __pr_out_handle_start(dl, tb, true, true);
2421}
2422
2423static void pr_out_handle_end(struct dl *dl)
2424{
2425        if (dl->json_output)
2426                close_json_object();
2427        else
2428                __pr_out_newline();
2429}
2430
2431static void pr_out_handle(struct dl *dl, struct nlattr **tb)
2432{
2433        __pr_out_handle_start(dl, tb, false, false);
2434        pr_out_handle_end(dl);
2435}
2436
2437static bool cmp_arr_last_port_handle(struct dl *dl, const char *bus_name,
2438                                     const char *dev_name, uint32_t port_index)
2439{
2440        return cmp_arr_last_handle(dl, bus_name, dev_name) &&
2441               dl->arr_last.port_index == port_index;
2442}
2443
2444static void arr_last_port_handle_set(struct dl *dl, const char *bus_name,
2445                                     const char *dev_name, uint32_t port_index)
2446{
2447        arr_last_handle_set(dl, bus_name, dev_name);
2448        dl->arr_last.port_index = port_index;
2449}
2450
2451static bool should_arr_last_port_handle_start(struct dl *dl,
2452                                              const char *bus_name,
2453                                              const char *dev_name,
2454                                              uint32_t port_index)
2455{
2456        return !cmp_arr_last_port_handle(dl, bus_name, dev_name, port_index);
2457}
2458
2459static bool should_arr_last_port_handle_end(struct dl *dl,
2460                                            const char *bus_name,
2461                                            const char *dev_name,
2462                                            uint32_t port_index)
2463{
2464        return dl->arr_last.present &&
2465               !cmp_arr_last_port_handle(dl, bus_name, dev_name, port_index);
2466}
2467
2468static void __pr_out_port_handle_start(struct dl *dl, const char *bus_name,
2469                                       const char *dev_name,
2470                                       uint32_t port_index, bool try_nice,
2471                                       bool array)
2472{
2473        static char buf[64];
2474        char *ifname = NULL;
2475
2476        if (dl->no_nice_names || !try_nice ||
2477            ifname_map_rev_lookup(dl, bus_name, dev_name,
2478                                  port_index, &ifname) != 0)
2479                sprintf(buf, "%s/%s/%d", bus_name, dev_name, port_index);
2480        else
2481                sprintf(buf, "%s", ifname);
2482
2483        if (dl->json_output) {
2484                if (array) {
2485                        if (should_arr_last_port_handle_end(dl, bus_name,
2486                                                            dev_name,
2487                                                            port_index))
2488                                close_json_array(PRINT_JSON, NULL);
2489                        if (should_arr_last_port_handle_start(dl, bus_name,
2490                                                              dev_name,
2491                                                              port_index)) {
2492                                open_json_array(PRINT_JSON, buf);
2493                                open_json_object(NULL);
2494                                arr_last_port_handle_set(dl, bus_name, dev_name,
2495                                                         port_index);
2496                        } else {
2497                                open_json_object(NULL);
2498                        }
2499                } else {
2500                        open_json_object(buf);
2501                }
2502        } else {
2503                if (array) {
2504                        if (should_arr_last_port_handle_end(dl, bus_name, dev_name, port_index))
2505                                __pr_out_indent_dec();
2506                        if (should_arr_last_port_handle_start(dl, bus_name,
2507                                                              dev_name, port_index)) {
2508                                pr_out("%s:", buf);
2509                                __pr_out_newline();
2510                                __pr_out_indent_inc();
2511                                arr_last_port_handle_set(dl, bus_name, dev_name, port_index);
2512                        }
2513                } else {
2514                        pr_out("%s:", buf);
2515                }
2516        }
2517}
2518
2519static void pr_out_port_handle_start(struct dl *dl, struct nlattr **tb, bool try_nice)
2520{
2521        const char *bus_name;
2522        const char *dev_name;
2523        uint32_t port_index;
2524
2525        bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
2526        dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
2527        port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]);
2528        __pr_out_port_handle_start(dl, bus_name, dev_name, port_index, try_nice, false);
2529}
2530
2531static void pr_out_port_handle_start_arr(struct dl *dl, struct nlattr **tb, bool try_nice)
2532{
2533        const char *bus_name;
2534        const char *dev_name;
2535        uint32_t port_index;
2536
2537        bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
2538        dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
2539        port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]);
2540        __pr_out_port_handle_start(dl, bus_name, dev_name, port_index, try_nice, true);
2541}
2542
2543static void pr_out_port_handle_end(struct dl *dl)
2544{
2545        if (dl->json_output)
2546                close_json_object();
2547        else
2548                pr_out("\n");
2549}
2550
2551static void pr_out_region_chunk_start(struct dl *dl, uint64_t addr)
2552{
2553        if (dl->json_output) {
2554                print_uint(PRINT_JSON, "address", NULL, addr);
2555                open_json_array(PRINT_JSON, "data");
2556        }
2557}
2558
2559static void pr_out_region_chunk_end(struct dl *dl)
2560{
2561        if (dl->json_output)
2562                close_json_array(PRINT_JSON, NULL);
2563}
2564
2565static void pr_out_region_chunk(struct dl *dl, uint8_t *data, uint32_t len,
2566                                uint64_t addr)
2567{
2568        static uint64_t align_val;
2569        uint32_t i = 0;
2570
2571        pr_out_region_chunk_start(dl, addr);
2572        while (i < len) {
2573                if (!dl->json_output)
2574                        if (!(align_val % 16))
2575                                pr_out("%s%016"PRIx64" ",
2576                                       align_val ? "\n" : "",
2577                                       addr);
2578
2579                align_val++;
2580
2581                if (dl->json_output)
2582                        print_int(PRINT_JSON, NULL, NULL, data[i]);
2583                else
2584                        pr_out("%02x ", data[i]);
2585
2586                addr++;
2587                i++;
2588        }
2589        pr_out_region_chunk_end(dl);
2590}
2591
2592static void pr_out_stats(struct dl *dl, struct nlattr *nla_stats)
2593{
2594        struct nlattr *tb[DEVLINK_ATTR_STATS_MAX + 1] = {};
2595        int err;
2596
2597        if (!dl->stats)
2598                return;
2599
2600        err = mnl_attr_parse_nested(nla_stats, attr_stats_cb, tb);
2601        if (err != MNL_CB_OK)
2602                return;
2603
2604        pr_out_object_start(dl, "stats");
2605        pr_out_object_start(dl, "rx");
2606        if (tb[DEVLINK_ATTR_STATS_RX_BYTES])
2607                pr_out_u64(dl, "bytes",
2608                           mnl_attr_get_u64(tb[DEVLINK_ATTR_STATS_RX_BYTES]));
2609        if (tb[DEVLINK_ATTR_STATS_RX_PACKETS])
2610                pr_out_u64(dl, "packets",
2611                           mnl_attr_get_u64(tb[DEVLINK_ATTR_STATS_RX_PACKETS]));
2612        if (tb[DEVLINK_ATTR_STATS_RX_DROPPED])
2613                pr_out_u64(dl, "dropped",
2614                           mnl_attr_get_u64(tb[DEVLINK_ATTR_STATS_RX_DROPPED]));
2615        pr_out_object_end(dl);
2616        pr_out_object_end(dl);
2617}
2618
2619static const char *param_cmode_name(uint8_t cmode)
2620{
2621        switch (cmode) {
2622        case DEVLINK_PARAM_CMODE_RUNTIME:
2623                return PARAM_CMODE_RUNTIME_STR;
2624        case DEVLINK_PARAM_CMODE_DRIVERINIT:
2625                return PARAM_CMODE_DRIVERINIT_STR;
2626        case DEVLINK_PARAM_CMODE_PERMANENT:
2627                return PARAM_CMODE_PERMANENT_STR;
2628        default: return "<unknown type>";
2629        }
2630}
2631
2632static const char *reload_action_name(uint8_t reload_action)
2633{
2634        switch (reload_action) {
2635        case DEVLINK_RELOAD_ACTION_DRIVER_REINIT:
2636                return "driver_reinit";
2637        case DEVLINK_RELOAD_ACTION_FW_ACTIVATE:
2638                return "fw_activate";
2639        default:
2640                return "<unknown reload action>";
2641        }
2642}
2643
2644static const char *reload_limit_name(uint8_t reload_limit)
2645{
2646        switch (reload_limit) {
2647        case DEVLINK_RELOAD_LIMIT_UNSPEC:
2648                return "unspecified";
2649        case DEVLINK_RELOAD_LIMIT_NO_RESET:
2650                return "no_reset";
2651        default:
2652                return "<unknown reload action>";
2653        }
2654}
2655
2656static const char *eswitch_mode_name(uint32_t mode)
2657{
2658        switch (mode) {
2659        case DEVLINK_ESWITCH_MODE_LEGACY: return ESWITCH_MODE_LEGACY;
2660        case DEVLINK_ESWITCH_MODE_SWITCHDEV: return ESWITCH_MODE_SWITCHDEV;
2661        default: return "<unknown mode>";
2662        }
2663}
2664
2665static const char *eswitch_inline_mode_name(uint32_t mode)
2666{
2667        switch (mode) {
2668        case DEVLINK_ESWITCH_INLINE_MODE_NONE:
2669                return ESWITCH_INLINE_MODE_NONE;
2670        case DEVLINK_ESWITCH_INLINE_MODE_LINK:
2671                return ESWITCH_INLINE_MODE_LINK;
2672        case DEVLINK_ESWITCH_INLINE_MODE_NETWORK:
2673                return ESWITCH_INLINE_MODE_NETWORK;
2674        case DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT:
2675                return ESWITCH_INLINE_MODE_TRANSPORT;
2676        default:
2677                return "<unknown mode>";
2678        }
2679}
2680
2681static const char *eswitch_encap_mode_name(uint32_t mode)
2682{
2683        switch (mode) {
2684        case DEVLINK_ESWITCH_ENCAP_MODE_NONE:
2685                return ESWITCH_ENCAP_MODE_NONE;
2686        case DEVLINK_ESWITCH_ENCAP_MODE_BASIC:
2687                return ESWITCH_ENCAP_MODE_BASIC;
2688        default:
2689                return "<unknown mode>";
2690        }
2691}
2692
2693static void pr_out_eswitch(struct dl *dl, struct nlattr **tb)
2694{
2695        __pr_out_handle_start(dl, tb, true, false);
2696
2697        if (tb[DEVLINK_ATTR_ESWITCH_MODE]) {
2698                check_indent_newline(dl);
2699                print_string(PRINT_ANY, "mode", "mode %s",
2700                             eswitch_mode_name(mnl_attr_get_u16(
2701                                     tb[DEVLINK_ATTR_ESWITCH_MODE])));
2702        }
2703        if (tb[DEVLINK_ATTR_ESWITCH_INLINE_MODE]) {
2704                check_indent_newline(dl);
2705                print_string(PRINT_ANY, "inline-mode", "inline-mode %s",
2706                             eswitch_inline_mode_name(mnl_attr_get_u8(
2707                                     tb[DEVLINK_ATTR_ESWITCH_INLINE_MODE])));
2708        }
2709        if (tb[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]) {
2710                check_indent_newline(dl);
2711                print_string(PRINT_ANY, "encap-mode", "encap-mode %s",
2712                             eswitch_encap_mode_name(mnl_attr_get_u8(
2713                                    tb[DEVLINK_ATTR_ESWITCH_ENCAP_MODE])));
2714        }
2715
2716        pr_out_handle_end(dl);
2717}
2718
2719static int cmd_dev_eswitch_show_cb(const struct nlmsghdr *nlh, void *data)
2720{
2721        struct dl *dl = data;
2722        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2723        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
2724
2725        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2726        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
2727                return MNL_CB_ERROR;
2728        pr_out_eswitch(dl, tb);
2729        return MNL_CB_OK;
2730}
2731
2732static int cmd_dev_eswitch_show(struct dl *dl)
2733{
2734        struct nlmsghdr *nlh;
2735        int err;
2736
2737        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_ESWITCH_GET,
2738                               NLM_F_REQUEST | NLM_F_ACK);
2739
2740        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
2741        if (err)
2742                return err;
2743
2744        pr_out_section_start(dl, "dev");
2745        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_dev_eswitch_show_cb, dl);
2746        pr_out_section_end(dl);
2747        return err;
2748}
2749
2750static int cmd_dev_eswitch_set(struct dl *dl)
2751{
2752        struct nlmsghdr *nlh;
2753        int err;
2754
2755        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_ESWITCH_SET,
2756                               NLM_F_REQUEST | NLM_F_ACK);
2757
2758        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE,
2759                                DL_OPT_ESWITCH_MODE |
2760                                DL_OPT_ESWITCH_INLINE_MODE |
2761                                DL_OPT_ESWITCH_ENCAP_MODE);
2762
2763        if (err)
2764                return err;
2765
2766        if (dl->opts.present == 1) {
2767                pr_err("Need to set at least one option\n");
2768                return -ENOENT;
2769        }
2770
2771        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
2772}
2773
2774static int cmd_dev_eswitch(struct dl *dl)
2775{
2776        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
2777                cmd_dev_help();
2778                return 0;
2779        } else if (dl_argv_match(dl, "set")) {
2780                dl_arg_inc(dl);
2781                return cmd_dev_eswitch_set(dl);
2782        } else if (dl_argv_match(dl, "show")) {
2783                dl_arg_inc(dl);
2784                return cmd_dev_eswitch_show(dl);
2785        }
2786        pr_err("Command \"%s\" not found\n", dl_argv(dl));
2787        return -ENOENT;
2788}
2789
2790struct param_val_conv {
2791        const char *name;
2792        const char *vstr;
2793        uint32_t vuint;
2794};
2795
2796static bool param_val_conv_exists(const struct param_val_conv *param_val_conv,
2797                                  uint32_t len, const char *name)
2798{
2799        uint32_t i;
2800
2801        for (i = 0; i < len; i++)
2802                if (!strcmp(param_val_conv[i].name, name))
2803                        return true;
2804
2805        return false;
2806}
2807
2808static int
2809param_val_conv_uint_get(const struct param_val_conv *param_val_conv,
2810                        uint32_t len, const char *name, const char *vstr,
2811                        uint32_t *vuint)
2812{
2813        uint32_t i;
2814
2815        for (i = 0; i < len; i++)
2816                if (!strcmp(param_val_conv[i].name, name) &&
2817                    !strcmp(param_val_conv[i].vstr, vstr)) {
2818                        *vuint = param_val_conv[i].vuint;
2819                        return 0;
2820                }
2821
2822        return -ENOENT;
2823}
2824
2825static int
2826param_val_conv_str_get(const struct param_val_conv *param_val_conv,
2827                       uint32_t len, const char *name, uint32_t vuint,
2828                       const char **vstr)
2829{
2830        uint32_t i;
2831
2832        for (i = 0; i < len; i++)
2833                if (!strcmp(param_val_conv[i].name, name) &&
2834                    param_val_conv[i].vuint == vuint) {
2835                        *vstr = param_val_conv[i].vstr;
2836                        return 0;
2837                }
2838
2839        return -ENOENT;
2840}
2841
2842static const struct param_val_conv param_val_conv[] = {
2843        {
2844                .name = "fw_load_policy",
2845                .vstr = "driver",
2846                .vuint = DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DRIVER,
2847        },
2848        {
2849                .name = "fw_load_policy",
2850                .vstr = "flash",
2851                .vuint = DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH,
2852        },
2853        {
2854                .name = "fw_load_policy",
2855                .vstr = "disk",
2856                .vuint = DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DISK,
2857        },
2858        {
2859                .name = "reset_dev_on_drv_probe",
2860                .vstr = "unknown",
2861                .vuint = DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_UNKNOWN,
2862        },
2863        {
2864                .name = "fw_load_policy",
2865                .vstr = "unknown",
2866                .vuint = DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_UNKNOWN,
2867        },
2868        {
2869                .name = "reset_dev_on_drv_probe",
2870                .vstr = "always",
2871                .vuint = DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_ALWAYS,
2872        },
2873        {
2874                .name = "reset_dev_on_drv_probe",
2875                .vstr = "never",
2876                .vuint = DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_NEVER,
2877        },
2878        {
2879                .name = "reset_dev_on_drv_probe",
2880                .vstr = "disk",
2881                .vuint = DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_DISK,
2882        },
2883};
2884
2885#define PARAM_VAL_CONV_LEN ARRAY_SIZE(param_val_conv)
2886
2887static void pr_out_param_value(struct dl *dl, const char *nla_name,
2888                               int nla_type, struct nlattr *nl)
2889{
2890        struct nlattr *nla_value[DEVLINK_ATTR_MAX + 1] = {};
2891        struct nlattr *val_attr;
2892        const char *vstr;
2893        bool conv_exists;
2894        int err;
2895
2896        err = mnl_attr_parse_nested(nl, attr_cb, nla_value);
2897        if (err != MNL_CB_OK)
2898                return;
2899
2900        if (!nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE] ||
2901            (nla_type != MNL_TYPE_FLAG &&
2902             !nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA]))
2903                return;
2904
2905        check_indent_newline(dl);
2906        print_string(PRINT_ANY, "cmode", "cmode %s",
2907                     param_cmode_name(mnl_attr_get_u8(nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE])));
2908
2909        val_attr = nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA];
2910
2911        conv_exists = param_val_conv_exists(param_val_conv, PARAM_VAL_CONV_LEN,
2912                                            nla_name);
2913
2914        switch (nla_type) {
2915        case MNL_TYPE_U8:
2916                if (conv_exists) {
2917                        err = param_val_conv_str_get(param_val_conv,
2918                                                     PARAM_VAL_CONV_LEN,
2919                                                     nla_name,
2920                                                     mnl_attr_get_u8(val_attr),
2921                                                     &vstr);
2922                        if (err)
2923                                return;
2924                        print_string(PRINT_ANY, "value", " value %s", vstr);
2925                } else {
2926                        print_uint(PRINT_ANY, "value", " value %u",
2927                                   mnl_attr_get_u8(val_attr));
2928                }
2929                break;
2930        case MNL_TYPE_U16:
2931                if (conv_exists) {
2932                        err = param_val_conv_str_get(param_val_conv,
2933                                                     PARAM_VAL_CONV_LEN,
2934                                                     nla_name,
2935                                                     mnl_attr_get_u16(val_attr),
2936                                                     &vstr);
2937                        if (err)
2938                                return;
2939                        print_string(PRINT_ANY, "value", " value %s", vstr);
2940                } else {
2941                        print_uint(PRINT_ANY, "value", " value %u",
2942                                   mnl_attr_get_u16(val_attr));
2943                }
2944                break;
2945        case MNL_TYPE_U32:
2946                if (conv_exists) {
2947                        err = param_val_conv_str_get(param_val_conv,
2948                                                     PARAM_VAL_CONV_LEN,
2949                                                     nla_name,
2950                                                     mnl_attr_get_u32(val_attr),
2951                                                     &vstr);
2952                        if (err)
2953                                return;
2954                        print_string(PRINT_ANY, "value", " value %s", vstr);
2955                } else {
2956                        print_uint(PRINT_ANY, "value", " value %u",
2957                                   mnl_attr_get_u32(val_attr));
2958                }
2959                break;
2960        case MNL_TYPE_STRING:
2961                print_string(PRINT_ANY, "value", " value %s",
2962                             mnl_attr_get_str(val_attr));
2963                break;
2964        case MNL_TYPE_FLAG:
2965                print_bool(PRINT_ANY, "value", " value %s", val_attr);
2966                break;
2967        }
2968}
2969
2970static void pr_out_param(struct dl *dl, struct nlattr **tb, bool array,
2971                         bool is_port_param)
2972{
2973        struct nlattr *nla_param[DEVLINK_ATTR_MAX + 1] = {};
2974        struct nlattr *param_value_attr;
2975        const char *nla_name;
2976        int nla_type;
2977        int err;
2978
2979        err = mnl_attr_parse_nested(tb[DEVLINK_ATTR_PARAM], attr_cb, nla_param);
2980        if (err != MNL_CB_OK)
2981                return;
2982        if (!nla_param[DEVLINK_ATTR_PARAM_NAME] ||
2983            !nla_param[DEVLINK_ATTR_PARAM_TYPE] ||
2984            !nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST])
2985                return;
2986
2987        if (array)
2988                if (is_port_param)
2989                        pr_out_port_handle_start_arr(dl, tb, false);
2990                else
2991                        pr_out_handle_start_arr(dl, tb);
2992        else
2993                if (is_port_param)
2994                        pr_out_port_handle_start(dl, tb, false);
2995                else
2996                        __pr_out_handle_start(dl, tb, true, false);
2997
2998        nla_type = mnl_attr_get_u8(nla_param[DEVLINK_ATTR_PARAM_TYPE]);
2999
3000        nla_name = mnl_attr_get_str(nla_param[DEVLINK_ATTR_PARAM_NAME]);
3001        check_indent_newline(dl);
3002        print_string(PRINT_ANY, "name", "name %s ", nla_name);
3003        if (!nla_param[DEVLINK_ATTR_PARAM_GENERIC])
3004                print_string(PRINT_ANY, "type", "type %s", "driver-specific");
3005        else
3006                print_string(PRINT_ANY, "type", "type %s", "generic");
3007
3008        pr_out_array_start(dl, "values");
3009        mnl_attr_for_each_nested(param_value_attr,
3010                                 nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST]) {
3011                pr_out_entry_start(dl);
3012                pr_out_param_value(dl, nla_name, nla_type, param_value_attr);
3013                pr_out_entry_end(dl);
3014        }
3015        pr_out_array_end(dl);
3016        if (is_port_param)
3017                pr_out_port_handle_end(dl);
3018        else
3019                pr_out_handle_end(dl);
3020}
3021
3022static int cmd_dev_param_show_cb(const struct nlmsghdr *nlh, void *data)
3023{
3024        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3025        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3026        struct dl *dl = data;
3027
3028        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3029        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3030            !tb[DEVLINK_ATTR_PARAM])
3031                return MNL_CB_ERROR;
3032        pr_out_param(dl, tb, true, false);
3033        return MNL_CB_OK;
3034}
3035
3036struct param_ctx {
3037        struct dl *dl;
3038        int nla_type;
3039        union {
3040                uint8_t vu8;
3041                uint16_t vu16;
3042                uint32_t vu32;
3043                const char *vstr;
3044                bool vbool;
3045        } value;
3046};
3047
3048static int cmd_dev_param_set_cb(const struct nlmsghdr *nlh, void *data)
3049{
3050        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3051        struct nlattr *nla_param[DEVLINK_ATTR_MAX + 1] = {};
3052        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3053        struct nlattr *param_value_attr;
3054        enum devlink_param_cmode cmode;
3055        struct param_ctx *ctx = data;
3056        struct dl *dl = ctx->dl;
3057        int nla_type;
3058        int err;
3059
3060        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3061        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3062            !tb[DEVLINK_ATTR_PARAM])
3063                return MNL_CB_ERROR;
3064
3065        err = mnl_attr_parse_nested(tb[DEVLINK_ATTR_PARAM], attr_cb, nla_param);
3066        if (err != MNL_CB_OK)
3067                return MNL_CB_ERROR;
3068
3069        if (!nla_param[DEVLINK_ATTR_PARAM_TYPE] ||
3070            !nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST])
3071                return MNL_CB_ERROR;
3072
3073        nla_type = mnl_attr_get_u8(nla_param[DEVLINK_ATTR_PARAM_TYPE]);
3074        mnl_attr_for_each_nested(param_value_attr,
3075                                 nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST]) {
3076                struct nlattr *nla_value[DEVLINK_ATTR_MAX + 1] = {};
3077                struct nlattr *val_attr;
3078
3079                err = mnl_attr_parse_nested(param_value_attr,
3080                                            attr_cb, nla_value);
3081                if (err != MNL_CB_OK)
3082                        return MNL_CB_ERROR;
3083
3084                if (!nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE] ||
3085                    (nla_type != MNL_TYPE_FLAG &&
3086                     !nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA]))
3087                        return MNL_CB_ERROR;
3088
3089                cmode = mnl_attr_get_u8(nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
3090                if (cmode == dl->opts.cmode) {
3091                        val_attr = nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA];
3092                        switch (nla_type) {
3093                        case MNL_TYPE_U8:
3094                                ctx->value.vu8 = mnl_attr_get_u8(val_attr);
3095                                break;
3096                        case MNL_TYPE_U16:
3097                                ctx->value.vu16 = mnl_attr_get_u16(val_attr);
3098                                break;
3099                        case MNL_TYPE_U32:
3100                                ctx->value.vu32 = mnl_attr_get_u32(val_attr);
3101                                break;
3102                        case MNL_TYPE_STRING:
3103                                ctx->value.vstr = mnl_attr_get_str(val_attr);
3104                                break;
3105                        case MNL_TYPE_FLAG:
3106                                ctx->value.vbool = val_attr ? true : false;
3107                                break;
3108                        }
3109                        break;
3110                }
3111        }
3112        ctx->nla_type = nla_type;
3113        return MNL_CB_OK;
3114}
3115
3116static int cmd_dev_param_set(struct dl *dl)
3117{
3118        struct param_ctx ctx = {};
3119        struct nlmsghdr *nlh;
3120        bool conv_exists;
3121        uint32_t val_u32 = 0;
3122        uint16_t val_u16;
3123        uint8_t val_u8;
3124        bool val_bool;
3125        int err;
3126
3127        err = dl_argv_parse(dl, DL_OPT_HANDLE |
3128                            DL_OPT_PARAM_NAME |
3129                            DL_OPT_PARAM_VALUE |
3130                            DL_OPT_PARAM_CMODE, 0);
3131        if (err)
3132                return err;
3133
3134        /* Get value type */
3135        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PARAM_GET,
3136                               NLM_F_REQUEST | NLM_F_ACK);
3137        dl_opts_put(nlh, dl);
3138
3139        ctx.dl = dl;
3140        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_dev_param_set_cb, &ctx);
3141        if (err)
3142                return err;
3143
3144        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PARAM_SET,
3145                               NLM_F_REQUEST | NLM_F_ACK);
3146        dl_opts_put(nlh, dl);
3147
3148        conv_exists = param_val_conv_exists(param_val_conv, PARAM_VAL_CONV_LEN,
3149                                            dl->opts.param_name);
3150
3151        mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_TYPE, ctx.nla_type);
3152        switch (ctx.nla_type) {
3153        case MNL_TYPE_U8:
3154                if (conv_exists) {
3155                        err = param_val_conv_uint_get(param_val_conv,
3156                                                      PARAM_VAL_CONV_LEN,
3157                                                      dl->opts.param_name,
3158                                                      dl->opts.param_value,
3159                                                      &val_u32);
3160                        val_u8 = val_u32;
3161                } else {
3162                        err = strtouint8_t(dl->opts.param_value, &val_u8);
3163                }
3164                if (err)
3165                        goto err_param_value_parse;
3166                if (val_u8 == ctx.value.vu8)
3167                        return 0;
3168                mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u8);
3169                break;
3170        case MNL_TYPE_U16:
3171                if (conv_exists) {
3172                        err = param_val_conv_uint_get(param_val_conv,
3173                                                      PARAM_VAL_CONV_LEN,
3174                                                      dl->opts.param_name,
3175                                                      dl->opts.param_value,
3176                                                      &val_u32);
3177                        val_u16 = val_u32;
3178                } else {
3179                        err = strtouint16_t(dl->opts.param_value, &val_u16);
3180                }
3181                if (err)
3182                        goto err_param_value_parse;
3183                if (val_u16 == ctx.value.vu16)
3184                        return 0;
3185                mnl_attr_put_u16(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u16);
3186                break;
3187        case MNL_TYPE_U32:
3188                if (conv_exists)
3189                        err = param_val_conv_uint_get(param_val_conv,
3190                                                      PARAM_VAL_CONV_LEN,
3191                                                      dl->opts.param_name,
3192                                                      dl->opts.param_value,
3193                                                      &val_u32);
3194                else
3195                        err = strtouint32_t(dl->opts.param_value, &val_u32);
3196                if (err)
3197                        goto err_param_value_parse;
3198                if (val_u32 == ctx.value.vu32)
3199                        return 0;
3200                mnl_attr_put_u32(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u32);
3201                break;
3202        case MNL_TYPE_FLAG:
3203                err = strtobool(dl->opts.param_value, &val_bool);
3204                if (err)
3205                        goto err_param_value_parse;
3206                if (val_bool == ctx.value.vbool)
3207                        return 0;
3208                if (val_bool)
3209                        mnl_attr_put(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA,
3210                                     0, NULL);
3211                break;
3212        case MNL_TYPE_STRING:
3213                mnl_attr_put_strz(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA,
3214                                  dl->opts.param_value);
3215                if (!strcmp(dl->opts.param_value, ctx.value.vstr))
3216                        return 0;
3217                break;
3218        default:
3219                printf("Value type not supported\n");
3220                return -ENOTSUP;
3221        }
3222        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
3223
3224err_param_value_parse:
3225        pr_err("Value \"%s\" is not a number or not within range\n",
3226               dl->opts.param_value);
3227        return err;
3228}
3229
3230static int cmd_port_param_show_cb(const struct nlmsghdr *nlh, void *data)
3231{
3232        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3233        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3234        struct dl *dl = data;
3235
3236        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3237        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3238            !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_PARAM])
3239                return MNL_CB_ERROR;
3240
3241        pr_out_param(dl, tb, true, true);
3242        return MNL_CB_OK;
3243}
3244
3245static int cmd_dev_param_show(struct dl *dl)
3246{
3247        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
3248        struct nlmsghdr *nlh;
3249        int err;
3250
3251        if (dl_argc(dl) == 0)
3252                flags |= NLM_F_DUMP;
3253
3254        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PARAM_GET, flags);
3255
3256        if (dl_argc(dl) > 0) {
3257                err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE |
3258                                        DL_OPT_PARAM_NAME, 0);
3259                if (err)
3260                        return err;
3261        }
3262
3263        pr_out_section_start(dl, "param");
3264        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_dev_param_show_cb, dl);
3265        pr_out_section_end(dl);
3266        return err;
3267}
3268
3269static int cmd_dev_param(struct dl *dl)
3270{
3271        if (dl_argv_match(dl, "help")) {
3272                cmd_dev_help();
3273                return 0;
3274        } else if (dl_argv_match(dl, "show") ||
3275                   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
3276                dl_arg_inc(dl);
3277                return cmd_dev_param_show(dl);
3278        } else if (dl_argv_match(dl, "set")) {
3279                dl_arg_inc(dl);
3280                return cmd_dev_param_set(dl);
3281        }
3282        pr_err("Command \"%s\" not found\n", dl_argv(dl));
3283        return -ENOENT;
3284}
3285
3286static void pr_out_action_stats(struct dl *dl, struct nlattr *action_stats)
3287{
3288        struct nlattr *tb_stats_entry[DEVLINK_ATTR_MAX + 1] = {};
3289        struct nlattr *nla_reload_stats_entry, *nla_limit, *nla_value;
3290        enum devlink_reload_limit limit;
3291        uint32_t value;
3292        int err;
3293
3294        mnl_attr_for_each_nested(nla_reload_stats_entry, action_stats) {
3295                err = mnl_attr_parse_nested(nla_reload_stats_entry, attr_cb,
3296                                            tb_stats_entry);
3297                if (err != MNL_CB_OK)
3298                        return;
3299
3300                nla_limit = tb_stats_entry[DEVLINK_ATTR_RELOAD_STATS_LIMIT];
3301                nla_value = tb_stats_entry[DEVLINK_ATTR_RELOAD_STATS_VALUE];
3302                if (!nla_limit || !nla_value)
3303                        return;
3304
3305                check_indent_newline(dl);
3306                limit = mnl_attr_get_u8(nla_limit);
3307                value = mnl_attr_get_u32(nla_value);
3308                print_uint_name_value(reload_limit_name(limit), value);
3309        }
3310}
3311
3312static void pr_out_reload_stats(struct dl *dl, struct nlattr *reload_stats)
3313{
3314        struct nlattr *nla_action_info, *nla_action, *nla_action_stats;
3315        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3316        enum devlink_reload_action action;
3317        int err;
3318
3319        mnl_attr_for_each_nested(nla_action_info, reload_stats) {
3320                err = mnl_attr_parse_nested(nla_action_info, attr_cb, tb);
3321                if (err != MNL_CB_OK)
3322                        return;
3323                nla_action = tb[DEVLINK_ATTR_RELOAD_ACTION];
3324                nla_action_stats = tb[DEVLINK_ATTR_RELOAD_ACTION_STATS];
3325                if (!nla_action || !nla_action_stats)
3326                        return;
3327
3328                action = mnl_attr_get_u8(nla_action);
3329                pr_out_object_start(dl, reload_action_name(action));
3330                pr_out_action_stats(dl, nla_action_stats);
3331                pr_out_object_end(dl);
3332        }
3333}
3334
3335static void pr_out_reload_data(struct dl *dl, struct nlattr **tb)
3336{
3337        struct nlattr *nla_reload_stats, *nla_remote_reload_stats;
3338        struct nlattr *tb_stats[DEVLINK_ATTR_MAX + 1] = {};
3339        uint8_t reload_failed = 0;
3340        int err;
3341
3342        if (tb[DEVLINK_ATTR_RELOAD_FAILED])
3343                reload_failed = mnl_attr_get_u8(tb[DEVLINK_ATTR_RELOAD_FAILED]);
3344
3345        if (reload_failed) {
3346                check_indent_newline(dl);
3347                print_bool(PRINT_ANY, "reload_failed", "reload_failed %s", true);
3348        }
3349        if (!tb[DEVLINK_ATTR_DEV_STATS] || !dl->stats)
3350                return;
3351        err = mnl_attr_parse_nested(tb[DEVLINK_ATTR_DEV_STATS], attr_cb,
3352                                    tb_stats);
3353        if (err != MNL_CB_OK)
3354                return;
3355
3356        pr_out_object_start(dl, "stats");
3357
3358        nla_reload_stats = tb_stats[DEVLINK_ATTR_RELOAD_STATS];
3359        if (nla_reload_stats) {
3360                pr_out_object_start(dl, "reload");
3361                pr_out_reload_stats(dl, nla_reload_stats);
3362                pr_out_object_end(dl);
3363        }
3364        nla_remote_reload_stats = tb_stats[DEVLINK_ATTR_REMOTE_RELOAD_STATS];
3365        if (nla_remote_reload_stats) {
3366                pr_out_object_start(dl, "remote_reload");
3367                pr_out_reload_stats(dl, nla_remote_reload_stats);
3368                pr_out_object_end(dl);
3369        }
3370
3371        pr_out_object_end(dl);
3372}
3373
3374
3375static void pr_out_dev(struct dl *dl, struct nlattr **tb)
3376{
3377        if ((tb[DEVLINK_ATTR_RELOAD_FAILED] && mnl_attr_get_u8(tb[DEVLINK_ATTR_RELOAD_FAILED])) ||
3378            (tb[DEVLINK_ATTR_DEV_STATS] && dl->stats)) {
3379                __pr_out_handle_start(dl, tb, true, false);
3380                pr_out_reload_data(dl, tb);
3381                pr_out_handle_end(dl);
3382        } else {
3383                pr_out_handle(dl, tb);
3384        }
3385}
3386
3387static int cmd_dev_show_cb(const struct nlmsghdr *nlh, void *data)
3388{
3389        struct dl *dl = data;
3390        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3391        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3392
3393        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3394        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
3395                return MNL_CB_ERROR;
3396
3397        pr_out_dev(dl, tb);
3398        return MNL_CB_OK;
3399}
3400
3401static int cmd_dev_show(struct dl *dl)
3402{
3403        struct nlmsghdr *nlh;
3404        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
3405        int err;
3406
3407        if (dl_argc(dl) == 0)
3408                flags |= NLM_F_DUMP;
3409
3410        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_GET, flags);
3411
3412        if (dl_argc(dl) > 0) {
3413                err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
3414                if (err)
3415                        return err;
3416        }
3417
3418        pr_out_section_start(dl, "dev");
3419        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_dev_show_cb, dl);
3420        pr_out_section_end(dl);
3421        return err;
3422}
3423
3424static void pr_out_reload_actions_performed(struct dl *dl, struct nlattr **tb)
3425{
3426        struct nlattr *nla_actions_performed;
3427        struct nla_bitfield32 *actions;
3428        uint32_t actions_performed;
3429        uint16_t len;
3430        int action;
3431
3432        if (!tb[DEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED])
3433                return;
3434
3435        nla_actions_performed = tb[DEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED];
3436        len = mnl_attr_get_payload_len(nla_actions_performed);
3437        if (len != sizeof(*actions))
3438                return;
3439        actions = mnl_attr_get_payload(nla_actions_performed);
3440        if (!actions)
3441                return;
3442        g_new_line_count = 1; /* Avoid extra new line in non-json print */
3443        pr_out_array_start(dl, "reload_actions_performed");
3444        actions_performed = actions->value & actions->selector;
3445        for (action = 0; action <= DEVLINK_RELOAD_ACTION_MAX; action++) {
3446                if (BIT(action) & actions_performed) {
3447                        check_indent_newline(dl);
3448                        print_string(PRINT_ANY, NULL, "%s",
3449                                     reload_action_name(action));
3450                }
3451        }
3452        pr_out_array_end(dl);
3453        if (!dl->json_output)
3454                __pr_out_newline();
3455}
3456
3457static int cmd_dev_reload_cb(const struct nlmsghdr *nlh, void *data)
3458{
3459        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3460        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3461        struct dl *dl = data;
3462
3463        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3464        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3465            !tb[DEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED])
3466                return MNL_CB_ERROR;
3467
3468        pr_out_section_start(dl, "reload");
3469        pr_out_reload_actions_performed(dl, tb);
3470        pr_out_section_end(dl);
3471
3472        return MNL_CB_OK;
3473}
3474
3475static int cmd_dev_reload(struct dl *dl)
3476{
3477        struct nlmsghdr *nlh;
3478        int err;
3479
3480        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
3481                cmd_dev_help();
3482                return 0;
3483        }
3484
3485        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RELOAD,
3486                               NLM_F_REQUEST | NLM_F_ACK);
3487
3488        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE,
3489                                DL_OPT_NETNS | DL_OPT_RELOAD_ACTION |
3490                                DL_OPT_RELOAD_LIMIT);
3491        if (err)
3492                return err;
3493
3494        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_dev_reload_cb, dl);
3495}
3496
3497static void pr_out_versions_single(struct dl *dl, const struct nlmsghdr *nlh,
3498                                   const char *name, int type)
3499{
3500        struct nlattr *version;
3501
3502        mnl_attr_for_each(version, nlh, sizeof(struct genlmsghdr)) {
3503                struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3504                const char *ver_value;
3505                const char *ver_name;
3506                int err;
3507
3508                if (mnl_attr_get_type(version) != type)
3509                        continue;
3510
3511                err = mnl_attr_parse_nested(version, attr_cb, tb);
3512                if (err != MNL_CB_OK)
3513                        continue;
3514
3515                if (!tb[DEVLINK_ATTR_INFO_VERSION_NAME] ||
3516                    !tb[DEVLINK_ATTR_INFO_VERSION_VALUE])
3517                        continue;
3518
3519                if (name) {
3520                        pr_out_object_start(dl, name);
3521                        name = NULL;
3522                }
3523
3524                ver_name = mnl_attr_get_str(tb[DEVLINK_ATTR_INFO_VERSION_NAME]);
3525                ver_value = mnl_attr_get_str(tb[DEVLINK_ATTR_INFO_VERSION_VALUE]);
3526
3527                check_indent_newline(dl);
3528                print_string_name_value(ver_name, ver_value);
3529                if (!dl->json_output)
3530                        __pr_out_newline();
3531        }
3532
3533        if (!name)
3534                pr_out_object_end(dl);
3535}
3536
3537static void pr_out_info(struct dl *dl, const struct nlmsghdr *nlh,
3538                        struct nlattr **tb, bool has_versions)
3539{
3540        __pr_out_handle_start(dl, tb, true, false);
3541
3542        __pr_out_indent_inc();
3543        if (tb[DEVLINK_ATTR_INFO_DRIVER_NAME]) {
3544                struct nlattr *nla_drv = tb[DEVLINK_ATTR_INFO_DRIVER_NAME];
3545
3546                if (!dl->json_output)
3547                        __pr_out_newline();
3548                check_indent_newline(dl);
3549                print_string(PRINT_ANY, "driver", "driver %s",
3550                             mnl_attr_get_str(nla_drv));
3551        }
3552
3553        if (tb[DEVLINK_ATTR_INFO_SERIAL_NUMBER]) {
3554                struct nlattr *nla_sn = tb[DEVLINK_ATTR_INFO_SERIAL_NUMBER];
3555
3556                if (!dl->json_output)
3557                        __pr_out_newline();
3558                check_indent_newline(dl);
3559                print_string(PRINT_ANY, "serial_number", "serial_number %s",
3560                             mnl_attr_get_str(nla_sn));
3561        }
3562
3563        if (tb[DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER]) {
3564                struct nlattr *nla_bsn = tb[DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER];
3565
3566                if (!dl->json_output)
3567                        __pr_out_newline();
3568                check_indent_newline(dl);
3569                print_string(PRINT_ANY, "board.serial_number", "board.serial_number %s",
3570                             mnl_attr_get_str(nla_bsn));
3571        }
3572        __pr_out_indent_dec();
3573
3574        if (has_versions) {
3575                pr_out_object_start(dl, "versions");
3576
3577                pr_out_versions_single(dl, nlh, "fixed",
3578                                       DEVLINK_ATTR_INFO_VERSION_FIXED);
3579                pr_out_versions_single(dl, nlh, "running",
3580                                       DEVLINK_ATTR_INFO_VERSION_RUNNING);
3581                pr_out_versions_single(dl, nlh, "stored",
3582                                       DEVLINK_ATTR_INFO_VERSION_STORED);
3583
3584                pr_out_object_end(dl);
3585        }
3586
3587        pr_out_handle_end(dl);
3588}
3589
3590static int cmd_versions_show_cb(const struct nlmsghdr *nlh, void *data)
3591{
3592        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3593        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3594        bool has_versions, has_info;
3595        struct dl *dl = data;
3596
3597        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3598
3599        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
3600                return MNL_CB_ERROR;
3601
3602        has_versions = tb[DEVLINK_ATTR_INFO_VERSION_FIXED] ||
3603                tb[DEVLINK_ATTR_INFO_VERSION_RUNNING] ||
3604                tb[DEVLINK_ATTR_INFO_VERSION_STORED];
3605        has_info = tb[DEVLINK_ATTR_INFO_DRIVER_NAME] ||
3606                tb[DEVLINK_ATTR_INFO_SERIAL_NUMBER] ||
3607                tb[DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER] ||
3608                has_versions;
3609
3610        if (has_info)
3611                pr_out_info(dl, nlh, tb, has_versions);
3612
3613        return MNL_CB_OK;
3614}
3615
3616static int cmd_dev_info(struct dl *dl)
3617{
3618        struct nlmsghdr *nlh;
3619        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
3620        int err;
3621
3622        if (dl_argv_match(dl, "help")) {
3623                cmd_dev_help();
3624                return 0;
3625        }
3626
3627        if (dl_argc(dl) == 0)
3628                flags |= NLM_F_DUMP;
3629
3630        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_INFO_GET, flags);
3631
3632        if (dl_argc(dl) > 0) {
3633                err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
3634                if (err)
3635                        return err;
3636        }
3637
3638        pr_out_section_start(dl, "info");
3639        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_versions_show_cb, dl);
3640        pr_out_section_end(dl);
3641        return err;
3642}
3643
3644struct cmd_dev_flash_status_ctx {
3645        struct dl *dl;
3646        struct timespec time_of_last_status;
3647        uint64_t status_msg_timeout;
3648        size_t elapsed_time_msg_len;
3649        char *last_msg;
3650        char *last_component;
3651        uint8_t not_first:1,
3652                last_pc:1,
3653                received_end:1,
3654                flash_done:1;
3655};
3656
3657static int nullstrcmp(const char *str1, const char *str2)
3658{
3659        if (str1 && str2)
3660                return strcmp(str1, str2);
3661        if (!str1 && !str2)
3662                return 0;
3663        return str1 ? 1 : -1;
3664}
3665
3666static void cmd_dev_flash_clear_elapsed_time(struct cmd_dev_flash_status_ctx *ctx)
3667{
3668        int i;
3669
3670        for (i = 0; i < ctx->elapsed_time_msg_len; i++)
3671                pr_out_tty("\b \b");
3672
3673        ctx->elapsed_time_msg_len = 0;
3674}
3675
3676static int cmd_dev_flash_status_cb(const struct nlmsghdr *nlh, void *data)
3677{
3678        struct cmd_dev_flash_status_ctx *ctx = data;
3679        struct dl_opts *opts = &ctx->dl->opts;
3680        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3681        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3682        const char *component = NULL;
3683        uint64_t done = 0, total = 0;
3684        const char *msg = NULL;
3685        const char *bus_name;
3686        const char *dev_name;
3687
3688        cmd_dev_flash_clear_elapsed_time(ctx);
3689
3690        if (genl->cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS &&
3691            genl->cmd != DEVLINK_CMD_FLASH_UPDATE_END)
3692                return MNL_CB_STOP;
3693
3694        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3695        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
3696                return MNL_CB_ERROR;
3697        bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
3698        dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
3699        if (strcmp(bus_name, opts->bus_name) ||
3700            strcmp(dev_name, opts->dev_name))
3701                return MNL_CB_ERROR;
3702
3703        if (genl->cmd == DEVLINK_CMD_FLASH_UPDATE_END) {
3704                pr_out("\n");
3705                free(ctx->last_msg);
3706                free(ctx->last_component);
3707                ctx->received_end = 1;
3708                return MNL_CB_STOP;
3709        }
3710
3711        if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG])
3712                msg = mnl_attr_get_str(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG]);
3713        if (tb[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT])
3714                component = mnl_attr_get_str(tb[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT]);
3715        if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE])
3716                done = mnl_attr_get_u64(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE]);
3717        if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL])
3718                total = mnl_attr_get_u64(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL]);
3719        if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TIMEOUT])
3720                ctx->status_msg_timeout = mnl_attr_get_u64(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TIMEOUT]);
3721        else
3722                ctx->status_msg_timeout = 0;
3723
3724        if (!nullstrcmp(msg, ctx->last_msg) &&
3725            !nullstrcmp(component, ctx->last_component) &&
3726            ctx->last_pc && ctx->not_first) {
3727                pr_out_tty("\b\b\b\b\b"); /* clean percentage */
3728        } else {
3729                /* only update the last status timestamp if the message changed */
3730                clock_gettime(CLOCK_MONOTONIC, &ctx->time_of_last_status);
3731
3732                if (ctx->not_first)
3733                        pr_out("\n");
3734                if (component) {
3735                        pr_out("[%s] ", component);
3736                        free(ctx->last_component);
3737                        ctx->last_component = strdup(component);
3738                }
3739                if (msg) {
3740                        pr_out("%s", msg);
3741                        free(ctx->last_msg);
3742                        ctx->last_msg = strdup(msg);
3743                }
3744        }
3745        if (total) {
3746                pr_out_tty(" %3"PRIu64"%%", (done * 100) / total);
3747                ctx->last_pc = 1;
3748        } else {
3749                ctx->last_pc = 0;
3750        }
3751        fflush(stdout);
3752        ctx->not_first = 1;
3753
3754        return MNL_CB_STOP;
3755}
3756
3757static void cmd_dev_flash_time_elapsed(struct cmd_dev_flash_status_ctx *ctx)
3758{
3759        struct timespec now, res;
3760
3761        clock_gettime(CLOCK_MONOTONIC, &now);
3762
3763        res.tv_sec = now.tv_sec - ctx->time_of_last_status.tv_sec;
3764        res.tv_nsec = now.tv_nsec - ctx->time_of_last_status.tv_nsec;
3765        if (res.tv_nsec < 0) {
3766                res.tv_sec--;
3767                res.tv_nsec += 1000000000L;
3768        }
3769
3770        /* Only begin displaying an elapsed time message if we've waited a few
3771         * seconds with no response, or the status message included a timeout
3772         * value.
3773         */
3774        if (res.tv_sec > 2 || ctx->status_msg_timeout) {
3775                uint64_t elapsed_m, elapsed_s;
3776                char msg[128];
3777                size_t len;
3778
3779                /* clear the last elapsed time message, if we have one */
3780                cmd_dev_flash_clear_elapsed_time(ctx);
3781
3782                elapsed_m = res.tv_sec / 60;
3783                elapsed_s = res.tv_sec % 60;
3784
3785                /**
3786                 * If we've elapsed a few seconds without receiving any status
3787                 * notification from the device, we display a time elapsed
3788                 * message. This has a few possible formats:
3789                 *
3790                 * 1) just time elapsed, when no timeout was provided
3791                 *    " ( Xm Ys )"
3792                 * 2) time elapsed out of a timeout that came from the device
3793                 *    driver via DEVLINK_CMD_FLASH_UPDATE_STATUS_TIMEOUT
3794                 *    " ( Xm Ys : Am Ys)"
3795                 * 3) time elapsed if we still receive no status after
3796                 *    reaching the provided timeout.
3797                 *    " ( Xm Ys : timeout reached )"
3798                 */
3799                if (!ctx->status_msg_timeout) {
3800                        len = snprintf(msg, sizeof(msg),
3801                                       " ( %"PRIu64"m %"PRIu64"s )", elapsed_m, elapsed_s);
3802                } else if (res.tv_sec <= ctx->status_msg_timeout) {
3803                        uint64_t timeout_m, timeout_s;
3804
3805                        timeout_m = ctx->status_msg_timeout / 60;
3806                        timeout_s = ctx->status_msg_timeout % 60;
3807
3808                        len = snprintf(msg, sizeof(msg),
3809                                       " ( %"PRIu64"m %"PRIu64"s : %"PRIu64"m %"PRIu64"s )",
3810                                       elapsed_m, elapsed_s, timeout_m, timeout_s);
3811                } else {
3812                        len = snprintf(msg, sizeof(msg),
3813                                       " ( %"PRIu64"m %"PRIu64"s : timeout reached )", elapsed_m, elapsed_s);
3814                }
3815
3816                ctx->elapsed_time_msg_len = len;
3817
3818                pr_out_tty("%s", msg);
3819                fflush(stdout);
3820        }
3821}
3822
3823static int cmd_dev_flash_fds_process(struct cmd_dev_flash_status_ctx *ctx,
3824                                     struct mnlu_gen_socket *nlg_ntf,
3825                                     int pipe_r)
3826{
3827        int nlfd = mnlg_socket_get_fd(nlg_ntf);
3828        struct timeval timeout;
3829        fd_set fds[3];
3830        int fdmax;
3831        int i;
3832        int err;
3833        int err2;
3834
3835        for (i = 0; i < 3; i++)
3836                FD_ZERO(&fds[i]);
3837        FD_SET(pipe_r, &fds[0]);
3838        fdmax = pipe_r + 1;
3839        FD_SET(nlfd, &fds[0]);
3840        if (nlfd >= fdmax)
3841                fdmax = nlfd + 1;
3842
3843        /* select only for a short while (1/10th of a second) in order to
3844         * allow periodically updating the screen with an elapsed time
3845         * indicator.
3846         */
3847        timeout.tv_sec = 0;
3848        timeout.tv_usec = 100000;
3849
3850        while (select(fdmax, &fds[0], &fds[1], &fds[2], &timeout) < 0) {
3851                if (errno == EINTR)
3852                        continue;
3853                pr_err("select() failed\n");
3854                return -errno;
3855        }
3856        if (FD_ISSET(nlfd, &fds[0])) {
3857                err = mnlu_gen_socket_recv_run(nlg_ntf,
3858                                               cmd_dev_flash_status_cb, ctx);
3859                if (err)
3860                        return err;
3861        }
3862        if (FD_ISSET(pipe_r, &fds[0])) {
3863                err = read(pipe_r, &err2, sizeof(err2));
3864                if (err == -1) {
3865                        pr_err("Failed to read pipe\n");
3866                        return -errno;
3867                }
3868                if (err2)
3869                        return err2;
3870                ctx->flash_done = 1;
3871        }
3872        cmd_dev_flash_time_elapsed(ctx);
3873        return 0;
3874}
3875
3876
3877static int cmd_dev_flash(struct dl *dl)
3878{
3879        struct cmd_dev_flash_status_ctx ctx = {.dl = dl,};
3880        struct mnlu_gen_socket nlg_ntf;
3881        struct nlmsghdr *nlh;
3882        int pipe_r, pipe_w;
3883        int pipe_fds[2];
3884        pid_t pid;
3885        int err;
3886
3887        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
3888                cmd_dev_help();
3889                return 0;
3890        }
3891
3892        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_FLASH_UPDATE,
3893                               NLM_F_REQUEST | NLM_F_ACK);
3894
3895        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_FLASH_FILE_NAME,
3896                                DL_OPT_FLASH_COMPONENT | DL_OPT_FLASH_OVERWRITE);
3897        if (err)
3898                return err;
3899
3900        err = mnlu_gen_socket_open(&nlg_ntf, DEVLINK_GENL_NAME,
3901                                   DEVLINK_GENL_VERSION);
3902        if (err)
3903                return err;
3904
3905        err = _mnlg_socket_group_add(&nlg_ntf, DEVLINK_GENL_MCGRP_CONFIG_NAME);
3906        if (err)
3907                goto err_socket;
3908
3909        err = pipe(pipe_fds);
3910        if (err == -1) {
3911                err = -errno;
3912                goto err_socket;
3913        }
3914        pipe_r = pipe_fds[0];
3915        pipe_w = pipe_fds[1];
3916
3917        pid = fork();
3918        if (pid == -1) {
3919                close(pipe_w);
3920                err = -errno;
3921                goto out;
3922        } else if (!pid) {
3923                /* In child, just execute the flash and pass returned
3924                 * value through pipe once it is done.
3925                 */
3926                int cc;
3927
3928                close(pipe_r);
3929                err = _mnlg_socket_send(&dl->nlg, nlh);
3930                cc = write(pipe_w, &err, sizeof(err));
3931                close(pipe_w);
3932                exit(cc != sizeof(err));
3933        }
3934        close(pipe_w);
3935
3936        /* initialize starting time to allow comparison for when to begin
3937         * displaying a time elapsed message.
3938         */
3939        clock_gettime(CLOCK_MONOTONIC, &ctx.time_of_last_status);
3940
3941        do {
3942                err = cmd_dev_flash_fds_process(&ctx, &nlg_ntf, pipe_r);
3943                if (err)
3944                        goto out;
3945        } while (!ctx.flash_done || (ctx.not_first && !ctx.received_end));
3946
3947        err = mnlu_gen_socket_recv_run(&dl->nlg, NULL, NULL);
3948
3949out:
3950        close(pipe_r);
3951err_socket:
3952        mnlu_gen_socket_close(&nlg_ntf);
3953        return err;
3954}
3955
3956static int cmd_dev(struct dl *dl)
3957{
3958        if (dl_argv_match(dl, "help")) {
3959                cmd_dev_help();
3960                return 0;
3961        } else if (dl_argv_match(dl, "show") ||
3962                   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
3963                dl_arg_inc(dl);
3964                return cmd_dev_show(dl);
3965        } else if (dl_argv_match(dl, "eswitch")) {
3966                dl_arg_inc(dl);
3967                return cmd_dev_eswitch(dl);
3968        } else if (dl_argv_match(dl, "reload")) {
3969                dl_arg_inc(dl);
3970                return cmd_dev_reload(dl);
3971        } else if (dl_argv_match(dl, "param")) {
3972                dl_arg_inc(dl);
3973                return cmd_dev_param(dl);
3974        } else if (dl_argv_match(dl, "info")) {
3975                dl_arg_inc(dl);
3976                return cmd_dev_info(dl);
3977        } else if (dl_argv_match(dl, "flash")) {
3978                dl_arg_inc(dl);
3979                return cmd_dev_flash(dl);
3980        }
3981        pr_err("Command \"%s\" not found\n", dl_argv(dl));
3982        return -ENOENT;
3983}
3984
3985static void cmd_port_help(void)
3986{
3987        pr_err("Usage: devlink port show [ DEV/PORT_INDEX ]\n");
3988        pr_err("       devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n");
3989        pr_err("       devlink port split DEV/PORT_INDEX count COUNT\n");
3990        pr_err("       devlink port unsplit DEV/PORT_INDEX\n");
3991        pr_err("       devlink port function set DEV/PORT_INDEX [ hw_addr ADDR ] [ state { active | inactive } ]\n");
3992        pr_err("       devlink port function rate { help | show | add | del | set }\n");
3993        pr_err("       devlink port param set DEV/PORT_INDEX name PARAMETER value VALUE cmode { permanent | driverinit | runtime }\n");
3994        pr_err("       devlink port param show [DEV/PORT_INDEX name PARAMETER]\n");
3995        pr_err("       devlink port health show [ DEV/PORT_INDEX reporter REPORTER_NAME ]\n");
3996        pr_err("       devlink port add DEV/PORT_INDEX flavour FLAVOUR pfnum PFNUM\n"
3997               "                      [ sfnum SFNUM ][ controller CNUM ]\n");
3998        pr_err("       devlink port del DEV/PORT_INDEX\n");
3999}
4000
4001static const char *port_type_name(uint32_t type)
4002{
4003        switch (type) {
4004        case DEVLINK_PORT_TYPE_NOTSET: return "notset";
4005        case DEVLINK_PORT_TYPE_AUTO: return "auto";
4006        case DEVLINK_PORT_TYPE_ETH: return "eth";
4007        case DEVLINK_PORT_TYPE_IB: return "ib";
4008        default: return "<unknown type>";
4009        }
4010}
4011
4012static const char *port_flavour_name(uint16_t flavour)
4013{
4014        const char *str;
4015
4016        str = str_map_lookup_u16(port_flavour_map, flavour);
4017        return str ? str : "<unknown flavour>";
4018}
4019
4020static void pr_out_port_pfvfsf_num(struct dl *dl, struct nlattr **tb)
4021{
4022        uint16_t fn_num;
4023
4024        if (tb[DEVLINK_ATTR_PORT_CONTROLLER_NUMBER])
4025                print_uint(PRINT_ANY, "controller", " controller %u",
4026                           mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_CONTROLLER_NUMBER]));
4027        if (tb[DEVLINK_ATTR_PORT_PCI_PF_NUMBER]) {
4028                fn_num = mnl_attr_get_u16(tb[DEVLINK_ATTR_PORT_PCI_PF_NUMBER]);
4029                print_uint(PRINT_ANY, "pfnum", " pfnum %u", fn_num);
4030        }
4031        if (tb[DEVLINK_ATTR_PORT_PCI_VF_NUMBER]) {
4032                fn_num = mnl_attr_get_u16(tb[DEVLINK_ATTR_PORT_PCI_VF_NUMBER]);
4033                print_uint(PRINT_ANY, "vfnum", " vfnum %u", fn_num);
4034        }
4035        if (tb[DEVLINK_ATTR_PORT_PCI_SF_NUMBER]) {
4036                fn_num = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_PCI_SF_NUMBER]);
4037                print_uint(PRINT_ANY, "sfnum", " sfnum %u", fn_num);
4038        }
4039        if (tb[DEVLINK_ATTR_PORT_EXTERNAL]) {
4040                uint8_t external;
4041
4042                external = mnl_attr_get_u8(tb[DEVLINK_ATTR_PORT_EXTERNAL]);
4043                print_bool(PRINT_ANY, "external", " external %s", external);
4044        }
4045}
4046
4047static const char *port_fn_state(uint8_t state)
4048{
4049        const char *str;
4050
4051        str = str_map_lookup_u8(port_fn_state_map, state);
4052        return str ? str : "<unknown state>";
4053}
4054
4055static const char *port_fn_opstate(uint8_t state)
4056{
4057        const char *str;
4058
4059        str = str_map_lookup_u8(port_fn_opstate_map, state);
4060        return str ? str : "<unknown state>";
4061}
4062
4063static void pr_out_port_function(struct dl *dl, struct nlattr **tb_port)
4064{
4065        struct nlattr *tb[DEVLINK_PORT_FUNCTION_ATTR_MAX + 1] = {};
4066        unsigned char *data;
4067        SPRINT_BUF(hw_addr);
4068        uint32_t len;
4069        int err;
4070
4071        if (!tb_port[DEVLINK_ATTR_PORT_FUNCTION])
4072                return;
4073
4074        err = mnl_attr_parse_nested(tb_port[DEVLINK_ATTR_PORT_FUNCTION],
4075                                    function_attr_cb, tb);
4076        if (err != MNL_CB_OK)
4077                return;
4078
4079        pr_out_object_start(dl, "function");
4080        check_indent_newline(dl);
4081
4082        if (tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR]) {
4083                len = mnl_attr_get_payload_len(tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR]);
4084                data = mnl_attr_get_payload(tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR]);
4085
4086                print_string(PRINT_ANY, "hw_addr", "hw_addr %s",
4087                             ll_addr_n2a(data, len, 0, hw_addr, sizeof(hw_addr)));
4088        }
4089        if (tb[DEVLINK_PORT_FN_ATTR_STATE]) {
4090                uint8_t state;
4091
4092                state = mnl_attr_get_u8(tb[DEVLINK_PORT_FN_ATTR_STATE]);
4093
4094                print_string(PRINT_ANY, "state", " state %s",
4095                             port_fn_state(state));
4096        }
4097        if (tb[DEVLINK_PORT_FN_ATTR_OPSTATE]) {
4098                uint8_t state;
4099
4100                state = mnl_attr_get_u8(tb[DEVLINK_PORT_FN_ATTR_OPSTATE]);
4101
4102                print_string(PRINT_ANY, "opstate", " opstate %s",
4103                             port_fn_opstate(state));
4104        }
4105
4106        if (!dl->json_output)
4107                __pr_out_indent_dec();
4108        pr_out_object_end(dl);
4109}
4110
4111static void pr_out_port(struct dl *dl, struct nlattr **tb)
4112{
4113        struct nlattr *pt_attr = tb[DEVLINK_ATTR_PORT_TYPE];
4114        struct nlattr *dpt_attr = tb[DEVLINK_ATTR_PORT_DESIRED_TYPE];
4115
4116        pr_out_port_handle_start(dl, tb, false);
4117        check_indent_newline(dl);
4118        if (pt_attr) {
4119                uint16_t port_type = mnl_attr_get_u16(pt_attr);
4120
4121                print_string(PRINT_ANY, "type", "type %s",
4122                             port_type_name(port_type));
4123                if (dpt_attr) {
4124                        uint16_t des_port_type = mnl_attr_get_u16(dpt_attr);
4125
4126                        if (port_type != des_port_type)
4127                                print_string(PRINT_ANY, "des_type", " des_type %s",
4128                                             port_type_name(des_port_type));
4129                }
4130        }
4131        if (tb[DEVLINK_ATTR_PORT_NETDEV_NAME]) {
4132                print_string(PRINT_ANY, "netdev", " netdev %s",
4133                             mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME]));
4134        }
4135        if (tb[DEVLINK_ATTR_PORT_IBDEV_NAME]) {
4136                print_string(PRINT_ANY, "ibdev", " ibdev %s",
4137                             mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_IBDEV_NAME]));
4138                }
4139        if (tb[DEVLINK_ATTR_PORT_FLAVOUR]) {
4140                uint16_t port_flavour =
4141                                mnl_attr_get_u16(tb[DEVLINK_ATTR_PORT_FLAVOUR]);
4142
4143                print_string(PRINT_ANY, "flavour", " flavour %s",
4144                             port_flavour_name(port_flavour));
4145
4146                switch (port_flavour) {
4147                case DEVLINK_PORT_FLAVOUR_PCI_PF:
4148                case DEVLINK_PORT_FLAVOUR_PCI_VF:
4149                case DEVLINK_PORT_FLAVOUR_PCI_SF:
4150                        pr_out_port_pfvfsf_num(dl, tb);
4151                        break;
4152                default:
4153                        break;
4154                }
4155        }
4156        if (tb[DEVLINK_ATTR_PORT_NUMBER]) {
4157                uint32_t port_number;
4158
4159                port_number = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_NUMBER]);
4160                print_uint(PRINT_ANY, "port", " port %u", port_number);
4161        }
4162        if (tb[DEVLINK_ATTR_PORT_SPLIT_GROUP])
4163                print_uint(PRINT_ANY, "split_group", " split_group %u",
4164                           mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_SPLIT_GROUP]));
4165        if (tb[DEVLINK_ATTR_PORT_SPLITTABLE])
4166                print_bool(PRINT_ANY, "splittable", " splittable %s",
4167                           mnl_attr_get_u8(tb[DEVLINK_ATTR_PORT_SPLITTABLE]));
4168        if (tb[DEVLINK_ATTR_PORT_LANES])
4169                print_uint(PRINT_ANY, "lanes", " lanes %u",
4170                           mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_LANES]));
4171
4172        pr_out_port_function(dl, tb);
4173        pr_out_port_handle_end(dl);
4174}
4175
4176static int cmd_port_show_cb(const struct nlmsghdr *nlh, void *data)
4177{
4178        struct dl *dl = data;
4179        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4180        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4181
4182        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4183        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4184            !tb[DEVLINK_ATTR_PORT_INDEX])
4185                return MNL_CB_ERROR;
4186        pr_out_port(dl, tb);
4187        return MNL_CB_OK;
4188}
4189
4190static int cmd_port_show(struct dl *dl)
4191{
4192        struct nlmsghdr *nlh;
4193        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
4194        int err;
4195
4196        if (dl_argc(dl) == 0)
4197                flags |= NLM_F_DUMP;
4198
4199        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_GET, flags);
4200
4201        if (dl_argc(dl) > 0) {
4202                err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
4203                if (err)
4204                        return err;
4205        }
4206
4207        pr_out_section_start(dl, "port");
4208        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_port_show_cb, dl);
4209        pr_out_section_end(dl);
4210        return err;
4211}
4212
4213static int cmd_port_set(struct dl *dl)
4214{
4215        struct nlmsghdr *nlh;
4216        int err;
4217
4218        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_SET,
4219                               NLM_F_REQUEST | NLM_F_ACK);
4220
4221        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_TYPE, 0);
4222        if (err)
4223                return err;
4224
4225        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
4226}
4227
4228static int cmd_port_split(struct dl *dl)
4229{
4230        struct nlmsghdr *nlh;
4231        int err;
4232
4233        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_SPLIT,
4234                               NLM_F_REQUEST | NLM_F_ACK);
4235
4236        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_COUNT, 0);
4237        if (err)
4238                return err;
4239
4240        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
4241}
4242
4243static int cmd_port_unsplit(struct dl *dl)
4244{
4245        struct nlmsghdr *nlh;
4246        int err;
4247
4248        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_UNSPLIT,
4249                               NLM_F_REQUEST | NLM_F_ACK);
4250
4251        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
4252        if (err)
4253                return err;
4254
4255        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
4256}
4257
4258static int cmd_port_param_show(struct dl *dl)
4259{
4260        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
4261        struct nlmsghdr *nlh;
4262        int err;
4263
4264        if (dl_argc(dl) == 0)
4265                flags |= NLM_F_DUMP;
4266
4267        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_PARAM_GET,
4268                                          flags);
4269
4270        if (dl_argc(dl) > 0) {
4271                err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP |
4272                                        DL_OPT_PARAM_NAME, 0);
4273                if (err)
4274                        return err;
4275        }
4276
4277        pr_out_section_start(dl, "param");
4278        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_port_param_show_cb, dl);
4279        pr_out_section_end(dl);
4280
4281        return err;
4282}
4283
4284static void cmd_port_function_help(void)
4285{
4286        pr_err("Usage: devlink port function set DEV/PORT_INDEX [ hw_addr ADDR ] [ state STATE ]\n");
4287        pr_err("       devlink port function rate { help | show | add | del | set }\n");
4288}
4289
4290static int cmd_port_function_set(struct dl *dl)
4291{
4292        struct nlmsghdr *nlh;
4293        int err;
4294
4295        if (dl_no_arg(dl)) {
4296                cmd_port_function_help();
4297                return 0;
4298        }
4299        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_SET,
4300                                          NLM_F_REQUEST | NLM_F_ACK);
4301
4302        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP,
4303                                DL_OPT_PORT_FUNCTION_HW_ADDR | DL_OPT_PORT_FUNCTION_STATE);
4304        if (err)
4305                return err;
4306
4307        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
4308}
4309
4310static int cmd_port_param_set_cb(const struct nlmsghdr *nlh, void *data)
4311{
4312        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4313        struct nlattr *nla_param[DEVLINK_ATTR_MAX + 1] = {};
4314        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4315        struct nlattr *param_value_attr;
4316        enum devlink_param_cmode cmode;
4317        struct param_ctx *ctx = data;
4318        struct dl *dl = ctx->dl;
4319        int nla_type;
4320        int err;
4321
4322        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4323        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4324            !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_PARAM])
4325                return MNL_CB_ERROR;
4326
4327        err = mnl_attr_parse_nested(tb[DEVLINK_ATTR_PARAM], attr_cb, nla_param);
4328        if (err != MNL_CB_OK)
4329                return MNL_CB_ERROR;
4330
4331        if (!nla_param[DEVLINK_ATTR_PARAM_TYPE] ||
4332            !nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST])
4333                return MNL_CB_ERROR;
4334
4335        nla_type = mnl_attr_get_u8(nla_param[DEVLINK_ATTR_PARAM_TYPE]);
4336        mnl_attr_for_each_nested(param_value_attr,
4337                                 nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST]) {
4338                struct nlattr *nla_value[DEVLINK_ATTR_MAX + 1] = {};
4339                struct nlattr *val_attr;
4340
4341                err = mnl_attr_parse_nested(param_value_attr,
4342                                            attr_cb, nla_value);
4343                if (err != MNL_CB_OK)
4344                        return MNL_CB_ERROR;
4345
4346                if (!nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE] ||
4347                    (nla_type != MNL_TYPE_FLAG &&
4348                     !nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA]))
4349                        return MNL_CB_ERROR;
4350
4351                cmode = mnl_attr_get_u8(nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
4352                if (cmode == dl->opts.cmode) {
4353                        val_attr = nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA];
4354                        switch (nla_type) {
4355                        case MNL_TYPE_U8:
4356                                ctx->value.vu8 = mnl_attr_get_u8(val_attr);
4357                                break;
4358                        case MNL_TYPE_U16:
4359                                ctx->value.vu16 = mnl_attr_get_u16(val_attr);
4360                                break;
4361                        case MNL_TYPE_U32:
4362                                ctx->value.vu32 = mnl_attr_get_u32(val_attr);
4363                                break;
4364                        case MNL_TYPE_STRING:
4365                                ctx->value.vstr = mnl_attr_get_str(val_attr);
4366                                break;
4367                        case MNL_TYPE_FLAG:
4368                                ctx->value.vbool = val_attr ? true : false;
4369                                break;
4370                        }
4371                        break;
4372                }
4373        }
4374        ctx->nla_type = nla_type;
4375        return MNL_CB_OK;
4376}
4377
4378static int cmd_port_param_set(struct dl *dl)
4379{
4380        struct param_ctx ctx = {};
4381        struct nlmsghdr *nlh;
4382        bool conv_exists;
4383        uint32_t val_u32 = 0;
4384        uint16_t val_u16;
4385        uint8_t val_u8;
4386        bool val_bool;
4387        int err;
4388
4389        err = dl_argv_parse(dl, DL_OPT_HANDLEP |
4390                            DL_OPT_PARAM_NAME |
4391                            DL_OPT_PARAM_VALUE |
4392                            DL_OPT_PARAM_CMODE, 0);
4393        if (err)
4394                return err;
4395
4396        /* Get value type */
4397        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_PARAM_GET,
4398                                          NLM_F_REQUEST | NLM_F_ACK);
4399        dl_opts_put(nlh, dl);
4400
4401        ctx.dl = dl;
4402        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_port_param_set_cb, &ctx);
4403        if (err)
4404                return err;
4405
4406        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_PARAM_SET,
4407                                          NLM_F_REQUEST | NLM_F_ACK);
4408        dl_opts_put(nlh, dl);
4409
4410        conv_exists = param_val_conv_exists(param_val_conv, PARAM_VAL_CONV_LEN,
4411                                            dl->opts.param_name);
4412
4413        mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_TYPE, ctx.nla_type);
4414        switch (ctx.nla_type) {
4415        case MNL_TYPE_U8:
4416                if (conv_exists) {
4417                        err = param_val_conv_uint_get(param_val_conv,
4418                                                      PARAM_VAL_CONV_LEN,
4419                                                      dl->opts.param_name,
4420                                                      dl->opts.param_value,
4421                                                      &val_u32);
4422                        val_u8 = val_u32;
4423                } else {
4424                        err = strtouint8_t(dl->opts.param_value, &val_u8);
4425                }
4426                if (err)
4427                        goto err_param_value_parse;
4428                if (val_u8 == ctx.value.vu8)
4429                        return 0;
4430                mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u8);
4431                break;
4432        case MNL_TYPE_U16:
4433                if (conv_exists) {
4434                        err = param_val_conv_uint_get(param_val_conv,
4435                                                      PARAM_VAL_CONV_LEN,
4436                                                      dl->opts.param_name,
4437                                                      dl->opts.param_value,
4438                                                      &val_u32);
4439                        val_u16 = val_u32;
4440                } else {
4441                        err = strtouint16_t(dl->opts.param_value, &val_u16);
4442                }
4443                if (err)
4444                        goto err_param_value_parse;
4445                if (val_u16 == ctx.value.vu16)
4446                        return 0;
4447                mnl_attr_put_u16(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u16);
4448                break;
4449        case MNL_TYPE_U32:
4450                if (conv_exists)
4451                        err = param_val_conv_uint_get(param_val_conv,
4452                                                      PARAM_VAL_CONV_LEN,
4453                                                      dl->opts.param_name,
4454                                                      dl->opts.param_value,
4455                                                      &val_u32);
4456                else
4457                        err = strtouint32_t(dl->opts.param_value, &val_u32);
4458                if (err)
4459                        goto err_param_value_parse;
4460                if (val_u32 == ctx.value.vu32)
4461                        return 0;
4462                mnl_attr_put_u32(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u32);
4463                break;
4464        case MNL_TYPE_FLAG:
4465                err = strtobool(dl->opts.param_value, &val_bool);
4466                if (err)
4467                        goto err_param_value_parse;
4468                if (val_bool == ctx.value.vbool)
4469                        return 0;
4470                if (val_bool)
4471                        mnl_attr_put(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA,
4472                                     0, NULL);
4473                break;
4474        case MNL_TYPE_STRING:
4475                mnl_attr_put_strz(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA,
4476                                  dl->opts.param_value);
4477                if (!strcmp(dl->opts.param_value, ctx.value.vstr))
4478                        return 0;
4479                break;
4480        default:
4481                printf("Value type not supported\n");
4482                return -ENOTSUP;
4483        }
4484        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
4485
4486err_param_value_parse:
4487        pr_err("Value \"%s\" is not a number or not within range\n",
4488               dl->opts.param_value);
4489        return err;
4490}
4491
4492static int cmd_port_param(struct dl *dl)
4493{
4494        if (dl_argv_match(dl, "help")) {
4495                cmd_port_help();
4496                return 0;
4497        } else if (dl_argv_match(dl, "show") ||
4498                   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
4499                dl_arg_inc(dl);
4500                return cmd_port_param_show(dl);
4501        } else if (dl_argv_match(dl, "set")) {
4502                dl_arg_inc(dl);
4503                return cmd_port_param_set(dl);
4504        }
4505        pr_err("Command \"%s\" not found\n", dl_argv(dl));
4506        return -ENOENT;
4507}
4508
4509static void
4510pr_out_port_rate_handle_start(struct dl *dl, struct nlattr **tb, bool try_nice)
4511{
4512        const char *bus_name;
4513        const char *dev_name;
4514        const char *node_name;
4515        static char buf[64];
4516
4517        bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
4518        dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
4519        node_name = mnl_attr_get_str(tb[DEVLINK_ATTR_RATE_NODE_NAME]);
4520        sprintf(buf, "%s/%s/%s", bus_name, dev_name, node_name);
4521        if (dl->json_output)
4522                open_json_object(buf);
4523        else
4524                pr_out("%s:", buf);
4525}
4526
4527static char *port_rate_type_name(uint16_t type)
4528{
4529        switch (type) {
4530        case DEVLINK_RATE_TYPE_LEAF:
4531                return "leaf";
4532        case DEVLINK_RATE_TYPE_NODE:
4533                return "node";
4534        default:
4535                return "<unknown type>";
4536        }
4537}
4538
4539static void pr_out_port_fn_rate(struct dl *dl, struct nlattr **tb)
4540{
4541
4542        if (!tb[DEVLINK_ATTR_RATE_NODE_NAME])
4543                pr_out_port_handle_start(dl, tb, false);
4544        else
4545                pr_out_port_rate_handle_start(dl, tb, false);
4546        check_indent_newline(dl);
4547
4548        if (tb[DEVLINK_ATTR_RATE_TYPE]) {
4549                uint16_t type =
4550                        mnl_attr_get_u16(tb[DEVLINK_ATTR_RATE_TYPE]);
4551
4552                print_string(PRINT_ANY, "type", "type %s",
4553                                port_rate_type_name(type));
4554        }
4555        if (tb[DEVLINK_ATTR_RATE_TX_SHARE]) {
4556                uint64_t rate =
4557                        mnl_attr_get_u64(tb[DEVLINK_ATTR_RATE_TX_SHARE]);
4558
4559                if (rate)
4560                        print_rate(use_iec, PRINT_ANY, "tx_share",
4561                                   " tx_share %s", rate);
4562        }
4563        if (tb[DEVLINK_ATTR_RATE_TX_MAX]) {
4564                uint64_t rate =
4565                        mnl_attr_get_u64(tb[DEVLINK_ATTR_RATE_TX_MAX]);
4566
4567                if (rate)
4568                        print_rate(use_iec, PRINT_ANY, "tx_max",
4569                                   " tx_max %s", rate);
4570        }
4571        if (tb[DEVLINK_ATTR_RATE_PARENT_NODE_NAME]) {
4572                const char *parent =
4573                        mnl_attr_get_str(tb[DEVLINK_ATTR_RATE_PARENT_NODE_NAME]);
4574
4575                print_string(PRINT_ANY, "parent", " parent %s", parent);
4576        }
4577
4578        pr_out_port_handle_end(dl);
4579}
4580
4581static int cmd_port_fn_rate_show_cb(const struct nlmsghdr *nlh, void *data)
4582{
4583        struct dl *dl = data;
4584        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4585        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4586
4587        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4588        if ((!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4589             !tb[DEVLINK_ATTR_PORT_INDEX]) &&
4590            !tb[DEVLINK_ATTR_RATE_NODE_NAME]) {
4591                return MNL_CB_ERROR;
4592        }
4593        pr_out_port_fn_rate(dl, tb);
4594        return MNL_CB_OK;
4595}
4596
4597static void cmd_port_fn_rate_help(void)
4598{
4599        pr_err("Usage: devlink port function rate help\n");
4600        pr_err("       devlink port function rate show [ DEV/{ PORT_INDEX | NODE_NAME } ]\n");
4601        pr_err("       devlink port function rate add DEV/NODE_NAME\n");
4602        pr_err("               [ tx_share VAL ][ tx_max VAL ][ { parent NODE_NAME | noparent } ]\n");
4603        pr_err("       devlink port function rate del DEV/NODE_NAME\n");
4604        pr_err("       devlink port function rate set DEV/{ PORT_INDEX | NODE_NAME }\n");
4605        pr_err("               [ tx_share VAL ][ tx_max VAL ][ { parent NODE_NAME | noparent } ]\n\n");
4606        pr_err("       VAL - float or integer value in units of bits or bytes per second (bit|bps)\n");
4607        pr_err("       and SI (k-, m-, g-, t-) or IEC (ki-, mi-, gi-, ti-) case-insensitive prefix.\n");
4608        pr_err("       Bare number, means bits per second, is possible.\n\n");
4609        pr_err("       For details refer to devlink-rate(8) man page.\n");
4610}
4611
4612static int cmd_port_fn_rate_show(struct dl *dl)
4613{
4614        struct nlmsghdr *nlh;
4615        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
4616        int err;
4617
4618        if (dl_argc(dl) == 0)
4619                flags |= NLM_F_DUMP;
4620
4621        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RATE_GET, flags);
4622
4623        if (dl_argc(dl) > 0) {
4624                err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP |
4625                                        DL_OPT_PORT_FN_RATE_NODE_NAME, 0);
4626                if (err)
4627                        return err;
4628        }
4629
4630        pr_out_section_start(dl, "rate");
4631        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_port_fn_rate_show_cb, dl);
4632        pr_out_section_end(dl);
4633        return err;
4634}
4635
4636static int port_fn_check_tx_rates(uint64_t min_rate, uint64_t max_rate)
4637{
4638        if (max_rate && min_rate > max_rate) {
4639                pr_err("Invalid. Expected tx_share <= tx_max or tx_share == 0.\n");
4640                return -EINVAL;
4641        }
4642        return 0;
4643}
4644
4645static int port_fn_get_and_check_tx_rates(struct dl_opts *reply,
4646                                          struct dl_opts *request)
4647{
4648        uint64_t min = reply->rate_tx_share;
4649        uint64_t max = reply->rate_tx_max;
4650
4651        if (request->present & DL_OPT_PORT_FN_RATE_TX_SHARE)
4652                return port_fn_check_tx_rates(request->rate_tx_share, max);
4653        return port_fn_check_tx_rates(min, request->rate_tx_max);
4654}
4655
4656static int cmd_port_fn_rate_add(struct dl *dl)
4657{
4658        struct nlmsghdr *nlh;
4659        int err;
4660
4661        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RATE_NEW,
4662                                          NLM_F_REQUEST | NLM_F_ACK);
4663        err = dl_argv_parse_put(nlh, dl, DL_OPT_PORT_FN_RATE_NODE_NAME,
4664                                DL_OPT_PORT_FN_RATE_TX_SHARE |
4665                                DL_OPT_PORT_FN_RATE_TX_MAX);
4666        if (err)
4667                return err;
4668
4669        if ((dl->opts.present & DL_OPT_PORT_FN_RATE_TX_SHARE) &&
4670            (dl->opts.present & DL_OPT_PORT_FN_RATE_TX_MAX)) {
4671                err = port_fn_check_tx_rates(dl->opts.rate_tx_share,
4672                                             dl->opts.rate_tx_max);
4673                if (err)
4674                        return err;
4675        }
4676
4677        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
4678}
4679
4680static int cmd_port_fn_rate_del(struct dl *dl)
4681{
4682        struct nlmsghdr *nlh;
4683        int err;
4684
4685        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RATE_DEL,
4686                                          NLM_F_REQUEST | NLM_F_ACK);
4687        err = dl_argv_parse_put(nlh, dl, DL_OPT_PORT_FN_RATE_NODE_NAME, 0);
4688        if (err)
4689                return err;
4690
4691        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
4692}
4693
4694static int port_fn_get_rates_cb(const struct nlmsghdr *nlh, void *data)
4695{
4696        struct dl_opts *opts = data;
4697        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4698        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4699
4700        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4701        if ((!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4702             !tb[DEVLINK_ATTR_PORT_INDEX]) &&
4703            !tb[DEVLINK_ATTR_RATE_NODE_NAME]) {
4704                return MNL_CB_ERROR;
4705        }
4706
4707        if (tb[DEVLINK_ATTR_RATE_TX_SHARE])
4708                opts->rate_tx_share =
4709                        mnl_attr_get_u64(tb[DEVLINK_ATTR_RATE_TX_SHARE]);
4710        if (tb[DEVLINK_ATTR_RATE_TX_MAX])
4711                opts->rate_tx_max =
4712                        mnl_attr_get_u64(tb[DEVLINK_ATTR_RATE_TX_MAX]);
4713        return MNL_CB_OK;
4714}
4715
4716static int cmd_port_fn_rate_set(struct dl *dl)
4717{
4718        struct dl_opts tmp_opts = {0};
4719        struct nlmsghdr *nlh;
4720        int err;
4721
4722        err = dl_argv_parse(dl, DL_OPT_HANDLEP |
4723                                DL_OPT_PORT_FN_RATE_NODE_NAME,
4724                                DL_OPT_PORT_FN_RATE_TX_SHARE |
4725                                DL_OPT_PORT_FN_RATE_TX_MAX |
4726                                DL_OPT_PORT_FN_RATE_PARENT);
4727        if (err)
4728                return err;
4729
4730        if ((dl->opts.present & DL_OPT_PORT_FN_RATE_TX_SHARE) &&
4731            (dl->opts.present & DL_OPT_PORT_FN_RATE_TX_MAX)) {
4732                err = port_fn_check_tx_rates(dl->opts.rate_tx_share,
4733                                             dl->opts.rate_tx_max);
4734                if (err)
4735                        return err;
4736        } else if (dl->opts.present &
4737                   (DL_OPT_PORT_FN_RATE_TX_SHARE | DL_OPT_PORT_FN_RATE_TX_MAX)) {
4738                nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RATE_GET,
4739                                                  NLM_F_REQUEST | NLM_F_ACK);
4740                tmp_opts = dl->opts;
4741                dl->opts.present &= ~(DL_OPT_PORT_FN_RATE_TX_SHARE |
4742                                      DL_OPT_PORT_FN_RATE_TX_MAX |
4743                                      DL_OPT_PORT_FN_RATE_PARENT);
4744                dl_opts_put(nlh, dl);
4745                err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, port_fn_get_rates_cb,
4746                                             &dl->opts);
4747                if (err)
4748                        return err;
4749                err = port_fn_get_and_check_tx_rates(&dl->opts, &tmp_opts);
4750                if (err)
4751                        return err;
4752                dl->opts = tmp_opts;
4753        }
4754
4755        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RATE_SET,
4756                                          NLM_F_REQUEST | NLM_F_ACK);
4757        dl_opts_put(nlh, dl);
4758        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
4759}
4760
4761static int cmd_port_function_rate(struct dl *dl)
4762{
4763        if (dl_argv_match(dl, "help")) {
4764                cmd_port_fn_rate_help();
4765                return 0;
4766        } else if (dl_argv_match(dl, "show") || dl_no_arg(dl)) {
4767                dl_arg_inc(dl);
4768                return cmd_port_fn_rate_show(dl);
4769        } else if (dl_argv_match(dl, "add")) {
4770                dl_arg_inc(dl);
4771                return cmd_port_fn_rate_add(dl);
4772        } else if (dl_argv_match(dl, "del")) {
4773                dl_arg_inc(dl);
4774                return cmd_port_fn_rate_del(dl);
4775        } else if (dl_argv_match(dl, "set")) {
4776                dl_arg_inc(dl);
4777                return cmd_port_fn_rate_set(dl);
4778        }
4779        pr_err("Command \"%s\" not found\n", dl_argv(dl));
4780        return -ENOENT;
4781}
4782
4783static int cmd_port_function(struct dl *dl)
4784{
4785        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
4786                cmd_port_function_help();
4787                return 0;
4788        } else if (dl_argv_match(dl, "set")) {
4789                dl_arg_inc(dl);
4790                return cmd_port_function_set(dl);
4791        } else if (dl_argv_match(dl, "rate")) {
4792                dl_arg_inc(dl);
4793                return cmd_port_function_rate(dl);
4794        }
4795        pr_err("Command \"%s\" not found\n", dl_argv(dl));
4796        return -ENOENT;
4797}
4798
4799static int cmd_health(struct dl *dl);
4800static int __cmd_health_show(struct dl *dl, bool show_device, bool show_port);
4801
4802static void cmd_port_add_help(void)
4803{
4804        pr_err("       devlink port add DEV/PORT_INDEX flavour FLAVOUR pfnum PFNUM\n"
4805               "                      [ sfnum SFNUM ][ controller CNUM ]\n");
4806}
4807
4808static int cmd_port_add(struct dl *dl)
4809{
4810        struct nlmsghdr *nlh;
4811        int err;
4812
4813        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
4814                cmd_port_add_help();
4815                return 0;
4816        }
4817
4818        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_NEW,
4819                                          NLM_F_REQUEST | NLM_F_ACK);
4820
4821        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_HANDLEP |
4822                                DL_OPT_PORT_FLAVOUR | DL_OPT_PORT_PFNUMBER,
4823                                DL_OPT_PORT_SFNUMBER | DL_OPT_PORT_CONTROLLER);
4824        if (err)
4825                return err;
4826
4827        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_port_show_cb, dl);
4828}
4829
4830static void cmd_port_del_help(void)
4831{
4832        pr_err("       devlink port del DEV/PORT_INDEX\n");
4833}
4834
4835static int cmd_port_del(struct dl *dl)
4836{
4837        struct nlmsghdr *nlh;
4838        int err;
4839
4840        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
4841                cmd_port_del_help();
4842                return 0;
4843        }
4844
4845        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_DEL,
4846                                          NLM_F_REQUEST | NLM_F_ACK);
4847
4848        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
4849        if (err)
4850                return err;
4851
4852        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
4853}
4854
4855static int cmd_port(struct dl *dl)
4856{
4857        if (dl_argv_match(dl, "help")) {
4858                cmd_port_help();
4859                return 0;
4860        } else if (dl_argv_match(dl, "show") ||
4861                   dl_argv_match(dl, "list") ||  dl_no_arg(dl)) {
4862                dl_arg_inc(dl);
4863                return cmd_port_show(dl);
4864        } else if (dl_argv_match(dl, "set")) {
4865                dl_arg_inc(dl);
4866                return cmd_port_set(dl);
4867        } else if (dl_argv_match(dl, "split")) {
4868                dl_arg_inc(dl);
4869                return cmd_port_split(dl);
4870        } else if (dl_argv_match(dl, "unsplit")) {
4871                dl_arg_inc(dl);
4872                return cmd_port_unsplit(dl);
4873        } else if (dl_argv_match(dl, "param")) {
4874                dl_arg_inc(dl);
4875                return cmd_port_param(dl);
4876        } else if (dl_argv_match(dl, "function")) {
4877                dl_arg_inc(dl);
4878                return cmd_port_function(dl);
4879        } else if (dl_argv_match(dl, "health")) {
4880                dl_arg_inc(dl);
4881                if (dl_argv_match(dl, "list") || dl_no_arg(dl)
4882                    || (dl_argv_match(dl, "show") && dl_argc(dl) == 1)) {
4883                        dl_arg_inc(dl);
4884                        return __cmd_health_show(dl, false, true);
4885                } else {
4886                        return cmd_health(dl);
4887                }
4888        } else if (dl_argv_match(dl, "add")) {
4889                dl_arg_inc(dl);
4890                return cmd_port_add(dl);
4891        } else if (dl_argv_match(dl, "del")) {
4892                dl_arg_inc(dl);
4893                return cmd_port_del(dl);
4894        }
4895
4896        pr_err("Command \"%s\" not found\n", dl_argv(dl));
4897        return -ENOENT;
4898}
4899
4900static void cmd_sb_help(void)
4901{
4902        pr_err("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n");
4903        pr_err("       devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n");
4904        pr_err("       devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n");
4905        pr_err("                           size POOL_SIZE thtype { static | dynamic }\n");
4906        pr_err("       devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n");
4907        pr_err("                                   pool POOL_INDEX ]\n");
4908        pr_err("       devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n");
4909        pr_err("                                pool POOL_INDEX th THRESHOLD\n");
4910        pr_err("       devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
4911        pr_err("                                 type { ingress | egress } ]\n");
4912        pr_err("       devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
4913        pr_err("                              type { ingress | egress } pool POOL_INDEX\n");
4914        pr_err("                              th THRESHOLD\n");
4915        pr_err("       devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n");
4916        pr_err("       devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n");
4917        pr_err("       devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n");
4918}
4919
4920static void pr_out_sb(struct dl *dl, struct nlattr **tb)
4921{
4922        pr_out_handle_start_arr(dl, tb);
4923        check_indent_newline(dl);
4924        print_uint(PRINT_ANY, "sb", "sb %u",
4925                   mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
4926        print_uint(PRINT_ANY, "size", " size %u",
4927                   mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_SIZE]));
4928        print_uint(PRINT_ANY, "ing_pools", " ing_pools %u",
4929                   mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT]));
4930        print_uint(PRINT_ANY, "eg_pools", " eg_pools %u",
4931                   mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT]));
4932        print_uint(PRINT_ANY, "ing_tcs", " ing_tcs %u",
4933                   mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT]));
4934        print_uint(PRINT_ANY, "eg_tcs", " eg_tcs %u",
4935                   mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT]));
4936        pr_out_handle_end(dl);
4937}
4938
4939static int cmd_sb_show_cb(const struct nlmsghdr *nlh, void *data)
4940{
4941        struct dl *dl = data;
4942        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4943        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4944
4945        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4946        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4947            !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_SIZE] ||
4948            !tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT] ||
4949            !tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT] ||
4950            !tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT] ||
4951            !tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT])
4952                return MNL_CB_ERROR;
4953        pr_out_sb(dl, tb);
4954        return MNL_CB_OK;
4955}
4956
4957static int cmd_sb_show(struct dl *dl)
4958{
4959        struct nlmsghdr *nlh;
4960        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
4961        int err;
4962
4963        if (dl_argc(dl) == 0)
4964                flags |= NLM_F_DUMP;
4965
4966        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_GET, flags);
4967
4968        if (dl_argc(dl) > 0) {
4969                err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB);
4970                if (err)
4971                        return err;
4972        }
4973
4974        pr_out_section_start(dl, "sb");
4975        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_sb_show_cb, dl);
4976        pr_out_section_end(dl);
4977        return err;
4978}
4979
4980static const char *pool_type_name(uint8_t type)
4981{
4982        switch (type) {
4983        case DEVLINK_SB_POOL_TYPE_INGRESS: return "ingress";
4984        case DEVLINK_SB_POOL_TYPE_EGRESS: return "egress";
4985        default: return "<unknown type>";
4986        }
4987}
4988
4989static const char *threshold_type_name(uint8_t type)
4990{
4991        switch (type) {
4992        case DEVLINK_SB_THRESHOLD_TYPE_STATIC: return "static";
4993        case DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC: return "dynamic";
4994        default: return "<unknown type>";
4995        }
4996}
4997
4998static void pr_out_sb_pool(struct dl *dl, struct nlattr **tb)
4999{
5000        pr_out_handle_start_arr(dl, tb);
5001        check_indent_newline(dl);
5002        print_uint(PRINT_ANY, "sb", "sb %u",
5003                   mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
5004        print_uint(PRINT_ANY, "pool", " pool %u",
5005                   mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]));
5006        print_string(PRINT_ANY, "type", " type %s",
5007                     pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])));
5008        print_uint(PRINT_ANY, "size", " size %u",
5009                   mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_SIZE]));
5010        print_string(PRINT_ANY, "thtype", " thtype %s",
5011                     threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])));
5012        if (tb[DEVLINK_ATTR_SB_POOL_CELL_SIZE])
5013                print_uint(PRINT_ANY, "cell_size", " cell size %u",
5014                           mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_CELL_SIZE]));
5015        pr_out_handle_end(dl);
5016}
5017
5018static int cmd_sb_pool_show_cb(const struct nlmsghdr *nlh, void *data)
5019{
5020        struct dl *dl = data;
5021        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
5022        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
5023
5024        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5025        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5026            !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_INDEX] ||
5027            !tb[DEVLINK_ATTR_SB_POOL_TYPE] || !tb[DEVLINK_ATTR_SB_POOL_SIZE] ||
5028            !tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])
5029                return MNL_CB_ERROR;
5030        pr_out_sb_pool(dl, tb);
5031        return MNL_CB_OK;
5032}
5033
5034static int cmd_sb_pool_show(struct dl *dl)
5035{
5036        struct nlmsghdr *nlh;
5037        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
5038        int err;
5039
5040        if (dl_argc(dl) == 0)
5041                flags |= NLM_F_DUMP;
5042
5043        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_POOL_GET, flags);
5044
5045        if (dl_argc(dl) > 0) {
5046                err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL,
5047                                        DL_OPT_SB);
5048                if (err)
5049                        return err;
5050        }
5051
5052        pr_out_section_start(dl, "pool");
5053        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_sb_pool_show_cb, dl);
5054        pr_out_section_end(dl);
5055        return err;
5056}
5057
5058static int cmd_sb_pool_set(struct dl *dl)
5059{
5060        struct nlmsghdr *nlh;
5061        int err;
5062
5063        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_POOL_SET,
5064                               NLM_F_REQUEST | NLM_F_ACK);
5065
5066        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL |
5067                                DL_OPT_SB_SIZE | DL_OPT_SB_THTYPE, DL_OPT_SB);
5068        if (err)
5069                return err;
5070
5071        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
5072}
5073
5074static int cmd_sb_pool(struct dl *dl)
5075{
5076        if (dl_argv_match(dl, "help")) {
5077                cmd_sb_help();
5078                return 0;
5079        } else if (dl_argv_match(dl, "show") ||
5080                   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
5081                dl_arg_inc(dl);
5082                return cmd_sb_pool_show(dl);
5083        } else if (dl_argv_match(dl, "set")) {
5084                dl_arg_inc(dl);
5085                return cmd_sb_pool_set(dl);
5086        }
5087        pr_err("Command \"%s\" not found\n", dl_argv(dl));
5088        return -ENOENT;
5089}
5090
5091static void pr_out_sb_port_pool(struct dl *dl, struct nlattr **tb)
5092{
5093        pr_out_port_handle_start_arr(dl, tb, true);
5094        check_indent_newline(dl);
5095        print_uint(PRINT_ANY, "sb", "sb %u",
5096                   mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
5097        print_uint(PRINT_ANY, "pool", " pool %u",
5098                   mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]));
5099        print_uint(PRINT_ANY, "threshold", " threshold %u",
5100                   mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD]));
5101        pr_out_port_handle_end(dl);
5102}
5103
5104static int cmd_sb_port_pool_show_cb(const struct nlmsghdr *nlh, void *data)
5105{
5106        struct dl *dl = data;
5107        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
5108        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
5109
5110        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5111        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5112            !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
5113            !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD])
5114                return MNL_CB_ERROR;
5115        pr_out_sb_port_pool(dl, tb);
5116        return MNL_CB_OK;
5117}
5118
5119static int cmd_sb_port_pool_show(struct dl *dl)
5120{
5121        struct nlmsghdr *nlh;
5122        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
5123        int err;
5124
5125        if (dl_argc(dl) == 0)
5126                flags |= NLM_F_DUMP;
5127
5128        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags);
5129
5130        if (dl_argc(dl) > 0) {
5131                err = dl_argv_parse_put(nlh, dl,
5132                                        DL_OPT_HANDLEP | DL_OPT_SB_POOL,
5133                                        DL_OPT_SB);
5134                if (err)
5135                        return err;
5136        }
5137
5138        pr_out_section_start(dl, "port_pool");
5139        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_sb_port_pool_show_cb, dl);
5140        pr_out_section_end(dl);
5141        return 0;
5142}
5143
5144static int cmd_sb_port_pool_set(struct dl *dl)
5145{
5146        struct nlmsghdr *nlh;
5147        int err;
5148
5149        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_PORT_POOL_SET,
5150                               NLM_F_REQUEST | NLM_F_ACK);
5151
5152        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_POOL |
5153                                DL_OPT_SB_TH, DL_OPT_SB);
5154        if (err)
5155                return err;
5156
5157        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
5158}
5159
5160static int cmd_sb_port_pool(struct dl *dl)
5161{
5162        if (dl_argv_match(dl, "help")) {
5163                cmd_sb_help();
5164                return 0;
5165        } else if (dl_argv_match(dl, "show") ||
5166                   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
5167                dl_arg_inc(dl);
5168                return cmd_sb_port_pool_show(dl);
5169        } else if (dl_argv_match(dl, "set")) {
5170                dl_arg_inc(dl);
5171                return cmd_sb_port_pool_set(dl);
5172        }
5173        pr_err("Command \"%s\" not found\n", dl_argv(dl));
5174        return -ENOENT;
5175}
5176
5177static int cmd_sb_port(struct dl *dl)
5178{
5179        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
5180                cmd_sb_help();
5181                return 0;
5182        } else if (dl_argv_match(dl, "pool")) {
5183                dl_arg_inc(dl);
5184                return cmd_sb_port_pool(dl);
5185        }
5186        pr_err("Command \"%s\" not found\n", dl_argv(dl));
5187        return -ENOENT;
5188}
5189
5190static void pr_out_sb_tc_bind(struct dl *dl, struct nlattr **tb)
5191{
5192        pr_out_port_handle_start_arr(dl, tb, true);
5193        check_indent_newline(dl);
5194        print_uint(PRINT_ANY, "sb", "sb %u",
5195                   mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
5196        print_uint(PRINT_ANY, "tc", " tc %u",
5197                   mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]));
5198        print_string(PRINT_ANY, "type", " type %s",
5199                     pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])));
5200        print_uint(PRINT_ANY, "pool", " pool %u",
5201                   mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]));
5202        print_uint(PRINT_ANY, "threshold", " threshold %u",
5203                   mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD]));
5204        pr_out_port_handle_end(dl);
5205}
5206
5207static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr *nlh, void *data)
5208{
5209        struct dl *dl = data;
5210        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
5211        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
5212
5213        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5214        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5215            !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
5216            !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] ||
5217            !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD])
5218                return MNL_CB_ERROR;
5219        pr_out_sb_tc_bind(dl, tb);
5220        return MNL_CB_OK;
5221}
5222
5223static int cmd_sb_tc_bind_show(struct dl *dl)
5224{
5225        struct nlmsghdr *nlh;
5226        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
5227        int err;
5228
5229        if (dl_argc(dl) == 0)
5230                flags |= NLM_F_DUMP;
5231
5232        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags);
5233
5234        if (dl_argc(dl) > 0) {
5235                err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC |
5236                                        DL_OPT_SB_TYPE, DL_OPT_SB);
5237                if (err)
5238                        return err;
5239        }
5240
5241        pr_out_section_start(dl, "tc_bind");
5242        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_sb_tc_bind_show_cb, dl);
5243        pr_out_section_end(dl);
5244        return err;
5245}
5246
5247static int cmd_sb_tc_bind_set(struct dl *dl)
5248{
5249        struct nlmsghdr *nlh;
5250        int err;
5251
5252        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_SET,
5253                               NLM_F_REQUEST | NLM_F_ACK);
5254
5255        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC |
5256                                DL_OPT_SB_TYPE | DL_OPT_SB_POOL | DL_OPT_SB_TH,
5257                                DL_OPT_SB);
5258        if (err)
5259                return err;
5260
5261        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
5262}
5263
5264static int cmd_sb_tc_bind(struct dl *dl)
5265{
5266        if (dl_argv_match(dl, "help")) {
5267                cmd_sb_help();
5268                return 0;
5269        } else if (dl_argv_match(dl, "show") ||
5270                   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
5271                dl_arg_inc(dl);
5272                return cmd_sb_tc_bind_show(dl);
5273        } else if (dl_argv_match(dl, "set")) {
5274                dl_arg_inc(dl);
5275                return cmd_sb_tc_bind_set(dl);
5276        }
5277        pr_err("Command \"%s\" not found\n", dl_argv(dl));
5278        return -ENOENT;
5279}
5280
5281static int cmd_sb_tc(struct dl *dl)
5282{
5283        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
5284                cmd_sb_help();
5285                return 0;
5286        } else if (dl_argv_match(dl, "bind")) {
5287                dl_arg_inc(dl);
5288                return cmd_sb_tc_bind(dl);
5289        }
5290        pr_err("Command \"%s\" not found\n", dl_argv(dl));
5291        return -ENOENT;
5292}
5293
5294struct occ_item {
5295        struct list_head list;
5296        uint32_t index;
5297        uint32_t cur;
5298        uint32_t max;
5299        uint32_t bound_pool_index;
5300};
5301
5302struct occ_port {
5303        struct list_head list;
5304        char *bus_name;
5305        char *dev_name;
5306        uint32_t port_index;
5307        uint32_t sb_index;
5308        struct list_head pool_list;
5309        struct list_head ing_tc_list;
5310        struct list_head eg_tc_list;
5311};
5312
5313struct occ_show {
5314        struct dl *dl;
5315        int err;
5316        struct list_head port_list;
5317};
5318
5319static struct occ_item *occ_item_alloc(void)
5320{
5321        return calloc(1, sizeof(struct occ_item));
5322}
5323
5324static void occ_item_free(struct occ_item *occ_item)
5325{
5326        free(occ_item);
5327}
5328
5329static struct occ_port *occ_port_alloc(uint32_t port_index)
5330{
5331        struct occ_port *occ_port;
5332
5333        occ_port = calloc(1, sizeof(*occ_port));
5334        if (!occ_port)
5335                return NULL;
5336        occ_port->port_index = port_index;
5337        INIT_LIST_HEAD(&occ_port->pool_list);
5338        INIT_LIST_HEAD(&occ_port->ing_tc_list);
5339        INIT_LIST_HEAD(&occ_port->eg_tc_list);
5340        return occ_port;
5341}
5342
5343static void occ_port_free(struct occ_port *occ_port)
5344{
5345        struct occ_item *occ_item, *tmp;
5346
5347        list_for_each_entry_safe(occ_item, tmp, &occ_port->pool_list, list)
5348                occ_item_free(occ_item);
5349        list_for_each_entry_safe(occ_item, tmp, &occ_port->ing_tc_list, list)
5350                occ_item_free(occ_item);
5351        list_for_each_entry_safe(occ_item, tmp, &occ_port->eg_tc_list, list)
5352                occ_item_free(occ_item);
5353}
5354
5355static struct occ_show *occ_show_alloc(struct dl *dl)
5356{
5357        struct occ_show *occ_show;
5358
5359        occ_show = calloc(1, sizeof(*occ_show));
5360        if (!occ_show)
5361                return NULL;
5362        occ_show->dl = dl;
5363        INIT_LIST_HEAD(&occ_show->port_list);
5364        return occ_show;
5365}
5366
5367static void occ_show_free(struct occ_show *occ_show)
5368{
5369        struct occ_port *occ_port, *tmp;
5370
5371        list_for_each_entry_safe(occ_port, tmp, &occ_show->port_list, list)
5372                occ_port_free(occ_port);
5373}
5374
5375static struct occ_port *occ_port_get(struct occ_show *occ_show,
5376                                     struct nlattr **tb)
5377{
5378        struct occ_port *occ_port;
5379        uint32_t port_index;
5380
5381        port_index = mnl_attr_get_u32(