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        bool cmode_found;
3040        union {
3041                uint8_t vu8;
3042                uint16_t vu16;
3043                uint32_t vu32;
3044                const char *vstr;
3045                bool vbool;
3046        } value;
3047};
3048
3049static int cmd_dev_param_set_cb(const struct nlmsghdr *nlh, void *data)
3050{
3051        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3052        struct nlattr *nla_param[DEVLINK_ATTR_MAX + 1] = {};
3053        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3054        struct nlattr *param_value_attr;
3055        enum devlink_param_cmode cmode;
3056        struct param_ctx *ctx = data;
3057        struct dl *dl = ctx->dl;
3058        int nla_type;
3059        int err;
3060
3061        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3062        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3063            !tb[DEVLINK_ATTR_PARAM])
3064                return MNL_CB_ERROR;
3065
3066        err = mnl_attr_parse_nested(tb[DEVLINK_ATTR_PARAM], attr_cb, nla_param);
3067        if (err != MNL_CB_OK)
3068                return MNL_CB_ERROR;
3069
3070        if (!nla_param[DEVLINK_ATTR_PARAM_TYPE] ||
3071            !nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST])
3072                return MNL_CB_ERROR;
3073
3074        nla_type = mnl_attr_get_u8(nla_param[DEVLINK_ATTR_PARAM_TYPE]);
3075        mnl_attr_for_each_nested(param_value_attr,
3076                                 nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST]) {
3077                struct nlattr *nla_value[DEVLINK_ATTR_MAX + 1] = {};
3078                struct nlattr *val_attr;
3079
3080                err = mnl_attr_parse_nested(param_value_attr,
3081                                            attr_cb, nla_value);
3082                if (err != MNL_CB_OK)
3083                        return MNL_CB_ERROR;
3084
3085                if (!nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE] ||
3086                    (nla_type != MNL_TYPE_FLAG &&
3087                     !nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA]))
3088                        return MNL_CB_ERROR;
3089
3090                cmode = mnl_attr_get_u8(nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
3091                if (cmode == dl->opts.cmode) {
3092                        ctx->cmode_found = true;
3093                        val_attr = nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA];
3094                        switch (nla_type) {
3095                        case MNL_TYPE_U8:
3096                                ctx->value.vu8 = mnl_attr_get_u8(val_attr);
3097                                break;
3098                        case MNL_TYPE_U16:
3099                                ctx->value.vu16 = mnl_attr_get_u16(val_attr);
3100                                break;
3101                        case MNL_TYPE_U32:
3102                                ctx->value.vu32 = mnl_attr_get_u32(val_attr);
3103                                break;
3104                        case MNL_TYPE_STRING:
3105                                ctx->value.vstr = mnl_attr_get_str(val_attr);
3106                                break;
3107                        case MNL_TYPE_FLAG:
3108                                ctx->value.vbool = val_attr ? true : false;
3109                                break;
3110                        }
3111                        break;
3112                }
3113        }
3114        ctx->nla_type = nla_type;
3115        return MNL_CB_OK;
3116}
3117
3118static int cmd_dev_param_set(struct dl *dl)
3119{
3120        struct param_ctx ctx = {};
3121        struct nlmsghdr *nlh;
3122        bool conv_exists;
3123        uint32_t val_u32 = 0;
3124        uint16_t val_u16;
3125        uint8_t val_u8;
3126        bool val_bool;
3127        int err;
3128
3129        err = dl_argv_parse(dl, DL_OPT_HANDLE |
3130                            DL_OPT_PARAM_NAME |
3131                            DL_OPT_PARAM_VALUE |
3132                            DL_OPT_PARAM_CMODE, 0);
3133        if (err)
3134                return err;
3135
3136        /* Get value type */
3137        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PARAM_GET,
3138                               NLM_F_REQUEST | NLM_F_ACK);
3139        dl_opts_put(nlh, dl);
3140
3141        ctx.dl = dl;
3142        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_dev_param_set_cb, &ctx);
3143        if (err)
3144                return err;
3145        if (!ctx.cmode_found) {
3146                pr_err("Configuration mode not supported\n");
3147                return -ENOTSUP;
3148        }
3149
3150        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PARAM_SET,
3151                               NLM_F_REQUEST | NLM_F_ACK);
3152        dl_opts_put(nlh, dl);
3153
3154        conv_exists = param_val_conv_exists(param_val_conv, PARAM_VAL_CONV_LEN,
3155                                            dl->opts.param_name);
3156
3157        mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_TYPE, ctx.nla_type);
3158        switch (ctx.nla_type) {
3159        case MNL_TYPE_U8:
3160                if (conv_exists) {
3161                        err = param_val_conv_uint_get(param_val_conv,
3162                                                      PARAM_VAL_CONV_LEN,
3163                                                      dl->opts.param_name,
3164                                                      dl->opts.param_value,
3165                                                      &val_u32);
3166                        val_u8 = val_u32;
3167                } else {
3168                        err = strtouint8_t(dl->opts.param_value, &val_u8);
3169                }
3170                if (err)
3171                        goto err_param_value_parse;
3172                if (val_u8 == ctx.value.vu8)
3173                        return 0;
3174                mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u8);
3175                break;
3176        case MNL_TYPE_U16:
3177                if (conv_exists) {
3178                        err = param_val_conv_uint_get(param_val_conv,
3179                                                      PARAM_VAL_CONV_LEN,
3180                                                      dl->opts.param_name,
3181                                                      dl->opts.param_value,
3182                                                      &val_u32);
3183                        val_u16 = val_u32;
3184                } else {
3185                        err = strtouint16_t(dl->opts.param_value, &val_u16);
3186                }
3187                if (err)
3188                        goto err_param_value_parse;
3189                if (val_u16 == ctx.value.vu16)
3190                        return 0;
3191                mnl_attr_put_u16(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u16);
3192                break;
3193        case MNL_TYPE_U32:
3194                if (conv_exists)
3195                        err = param_val_conv_uint_get(param_val_conv,
3196                                                      PARAM_VAL_CONV_LEN,
3197                                                      dl->opts.param_name,
3198                                                      dl->opts.param_value,
3199                                                      &val_u32);
3200                else
3201                        err = strtouint32_t(dl->opts.param_value, &val_u32);
3202                if (err)
3203                        goto err_param_value_parse;
3204                if (val_u32 == ctx.value.vu32)
3205                        return 0;
3206                mnl_attr_put_u32(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u32);
3207                break;
3208        case MNL_TYPE_FLAG:
3209                err = strtobool(dl->opts.param_value, &val_bool);
3210                if (err)
3211                        goto err_param_value_parse;
3212                if (val_bool == ctx.value.vbool)
3213                        return 0;
3214                if (val_bool)
3215                        mnl_attr_put(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA,
3216                                     0, NULL);
3217                break;
3218        case MNL_TYPE_STRING:
3219                mnl_attr_put_strz(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA,
3220                                  dl->opts.param_value);
3221                if (!strcmp(dl->opts.param_value, ctx.value.vstr))
3222                        return 0;
3223                break;
3224        default:
3225                printf("Value type not supported\n");
3226                return -ENOTSUP;
3227        }
3228        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
3229
3230err_param_value_parse:
3231        pr_err("Value \"%s\" is not a number or not within range\n",
3232               dl->opts.param_value);
3233        return err;
3234}
3235
3236static int cmd_port_param_show_cb(const struct nlmsghdr *nlh, void *data)
3237{
3238        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3239        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3240        struct dl *dl = data;
3241
3242        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3243        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3244            !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_PARAM])
3245                return MNL_CB_ERROR;
3246
3247        pr_out_param(dl, tb, true, true);
3248        return MNL_CB_OK;
3249}
3250
3251static int cmd_dev_param_show(struct dl *dl)
3252{
3253        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
3254        struct nlmsghdr *nlh;
3255        int err;
3256
3257        if (dl_argc(dl) == 0)
3258                flags |= NLM_F_DUMP;
3259
3260        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PARAM_GET, flags);
3261
3262        if (dl_argc(dl) > 0) {
3263                err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE |
3264                                        DL_OPT_PARAM_NAME, 0);
3265                if (err)
3266                        return err;
3267        }
3268
3269        pr_out_section_start(dl, "param");
3270        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_dev_param_show_cb, dl);
3271        pr_out_section_end(dl);
3272        return err;
3273}
3274
3275static int cmd_dev_param(struct dl *dl)
3276{
3277        if (dl_argv_match(dl, "help")) {
3278                cmd_dev_help();
3279                return 0;
3280        } else if (dl_argv_match(dl, "show") ||
3281                   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
3282                dl_arg_inc(dl);
3283                return cmd_dev_param_show(dl);
3284        } else if (dl_argv_match(dl, "set")) {
3285                dl_arg_inc(dl);
3286                return cmd_dev_param_set(dl);
3287        }
3288        pr_err("Command \"%s\" not found\n", dl_argv(dl));
3289        return -ENOENT;
3290}
3291
3292static void pr_out_action_stats(struct dl *dl, struct nlattr *action_stats)
3293{
3294        struct nlattr *tb_stats_entry[DEVLINK_ATTR_MAX + 1] = {};
3295        struct nlattr *nla_reload_stats_entry, *nla_limit, *nla_value;
3296        enum devlink_reload_limit limit;
3297        uint32_t value;
3298        int err;
3299
3300        mnl_attr_for_each_nested(nla_reload_stats_entry, action_stats) {
3301                err = mnl_attr_parse_nested(nla_reload_stats_entry, attr_cb,
3302                                            tb_stats_entry);
3303                if (err != MNL_CB_OK)
3304                        return;
3305
3306                nla_limit = tb_stats_entry[DEVLINK_ATTR_RELOAD_STATS_LIMIT];
3307                nla_value = tb_stats_entry[DEVLINK_ATTR_RELOAD_STATS_VALUE];
3308                if (!nla_limit || !nla_value)
3309                        return;
3310
3311                check_indent_newline(dl);
3312                limit = mnl_attr_get_u8(nla_limit);
3313                value = mnl_attr_get_u32(nla_value);
3314                print_uint_name_value(reload_limit_name(limit), value);
3315        }
3316}
3317
3318static void pr_out_reload_stats(struct dl *dl, struct nlattr *reload_stats)
3319{
3320        struct nlattr *nla_action_info, *nla_action, *nla_action_stats;
3321        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3322        enum devlink_reload_action action;
3323        int err;
3324
3325        mnl_attr_for_each_nested(nla_action_info, reload_stats) {
3326                err = mnl_attr_parse_nested(nla_action_info, attr_cb, tb);
3327                if (err != MNL_CB_OK)
3328                        return;
3329                nla_action = tb[DEVLINK_ATTR_RELOAD_ACTION];
3330                nla_action_stats = tb[DEVLINK_ATTR_RELOAD_ACTION_STATS];
3331                if (!nla_action || !nla_action_stats)
3332                        return;
3333
3334                action = mnl_attr_get_u8(nla_action);
3335                pr_out_object_start(dl, reload_action_name(action));
3336                pr_out_action_stats(dl, nla_action_stats);
3337                pr_out_object_end(dl);
3338        }
3339}
3340
3341static void pr_out_reload_data(struct dl *dl, struct nlattr **tb)
3342{
3343        struct nlattr *nla_reload_stats, *nla_remote_reload_stats;
3344        struct nlattr *tb_stats[DEVLINK_ATTR_MAX + 1] = {};
3345        uint8_t reload_failed = 0;
3346        int err;
3347
3348        if (tb[DEVLINK_ATTR_RELOAD_FAILED])
3349                reload_failed = mnl_attr_get_u8(tb[DEVLINK_ATTR_RELOAD_FAILED]);
3350
3351        if (reload_failed) {
3352                check_indent_newline(dl);
3353                print_bool(PRINT_ANY, "reload_failed", "reload_failed %s", true);
3354        }
3355        if (!tb[DEVLINK_ATTR_DEV_STATS] || !dl->stats)
3356                return;
3357        err = mnl_attr_parse_nested(tb[DEVLINK_ATTR_DEV_STATS], attr_cb,
3358                                    tb_stats);
3359        if (err != MNL_CB_OK)
3360                return;
3361
3362        pr_out_object_start(dl, "stats");
3363
3364        nla_reload_stats = tb_stats[DEVLINK_ATTR_RELOAD_STATS];
3365        if (nla_reload_stats) {
3366                pr_out_object_start(dl, "reload");
3367                pr_out_reload_stats(dl, nla_reload_stats);
3368                pr_out_object_end(dl);
3369        }
3370        nla_remote_reload_stats = tb_stats[DEVLINK_ATTR_REMOTE_RELOAD_STATS];
3371        if (nla_remote_reload_stats) {
3372                pr_out_object_start(dl, "remote_reload");
3373                pr_out_reload_stats(dl, nla_remote_reload_stats);
3374                pr_out_object_end(dl);
3375        }
3376
3377        pr_out_object_end(dl);
3378}
3379
3380
3381static void pr_out_dev(struct dl *dl, struct nlattr **tb)
3382{
3383        if ((tb[DEVLINK_ATTR_RELOAD_FAILED] && mnl_attr_get_u8(tb[DEVLINK_ATTR_RELOAD_FAILED])) ||
3384            (tb[DEVLINK_ATTR_DEV_STATS] && dl->stats)) {
3385                __pr_out_handle_start(dl, tb, true, false);
3386                pr_out_reload_data(dl, tb);
3387                pr_out_handle_end(dl);
3388        } else {
3389                pr_out_handle(dl, tb);
3390        }
3391}
3392
3393static int cmd_dev_show_cb(const struct nlmsghdr *nlh, void *data)
3394{
3395        struct dl *dl = data;
3396        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3397        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3398
3399        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3400        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
3401                return MNL_CB_ERROR;
3402
3403        pr_out_dev(dl, tb);
3404        return MNL_CB_OK;
3405}
3406
3407static int cmd_dev_show(struct dl *dl)
3408{
3409        struct nlmsghdr *nlh;
3410        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
3411        int err;
3412
3413        if (dl_argc(dl) == 0)
3414                flags |= NLM_F_DUMP;
3415
3416        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_GET, flags);
3417
3418        if (dl_argc(dl) > 0) {
3419                err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
3420                if (err)
3421                        return err;
3422        }
3423
3424        pr_out_section_start(dl, "dev");
3425        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_dev_show_cb, dl);
3426        pr_out_section_end(dl);
3427        return err;
3428}
3429
3430static void pr_out_reload_actions_performed(struct dl *dl, struct nlattr **tb)
3431{
3432        struct nlattr *nla_actions_performed;
3433        struct nla_bitfield32 *actions;
3434        uint32_t actions_performed;
3435        uint16_t len;
3436        int action;
3437
3438        if (!tb[DEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED])
3439                return;
3440
3441        nla_actions_performed = tb[DEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED];
3442        len = mnl_attr_get_payload_len(nla_actions_performed);
3443        if (len != sizeof(*actions))
3444                return;
3445        actions = mnl_attr_get_payload(nla_actions_performed);
3446        if (!actions)
3447                return;
3448        g_new_line_count = 1; /* Avoid extra new line in non-json print */
3449        pr_out_array_start(dl, "reload_actions_performed");
3450        actions_performed = actions->value & actions->selector;
3451        for (action = 0; action <= DEVLINK_RELOAD_ACTION_MAX; action++) {
3452                if (BIT(action) & actions_performed) {
3453                        check_indent_newline(dl);
3454                        print_string(PRINT_ANY, NULL, "%s",
3455                                     reload_action_name(action));
3456                }
3457        }
3458        pr_out_array_end(dl);
3459        if (!dl->json_output)
3460                __pr_out_newline();
3461}
3462
3463static int cmd_dev_reload_cb(const struct nlmsghdr *nlh, void *data)
3464{
3465        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3466        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3467        struct dl *dl = data;
3468
3469        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3470        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3471            !tb[DEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED])
3472                return MNL_CB_ERROR;
3473
3474        pr_out_section_start(dl, "reload");
3475        pr_out_reload_actions_performed(dl, tb);
3476        pr_out_section_end(dl);
3477
3478        return MNL_CB_OK;
3479}
3480
3481static int cmd_dev_reload(struct dl *dl)
3482{
3483        struct nlmsghdr *nlh;
3484        int err;
3485
3486        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
3487                cmd_dev_help();
3488                return 0;
3489        }
3490
3491        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RELOAD,
3492                               NLM_F_REQUEST | NLM_F_ACK);
3493
3494        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE,
3495                                DL_OPT_NETNS | DL_OPT_RELOAD_ACTION |
3496                                DL_OPT_RELOAD_LIMIT);
3497        if (err)
3498                return err;
3499
3500        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_dev_reload_cb, dl);
3501}
3502
3503static void pr_out_versions_single(struct dl *dl, const struct nlmsghdr *nlh,
3504                                   const char *name, int type)
3505{
3506        struct nlattr *version;
3507
3508        mnl_attr_for_each(version, nlh, sizeof(struct genlmsghdr)) {
3509                struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3510                const char *ver_value;
3511                const char *ver_name;
3512                int err;
3513
3514                if (mnl_attr_get_type(version) != type)
3515                        continue;
3516
3517                err = mnl_attr_parse_nested(version, attr_cb, tb);
3518                if (err != MNL_CB_OK)
3519                        continue;
3520
3521                if (!tb[DEVLINK_ATTR_INFO_VERSION_NAME] ||
3522                    !tb[DEVLINK_ATTR_INFO_VERSION_VALUE])
3523                        continue;
3524
3525                if (name) {
3526                        pr_out_object_start(dl, name);
3527                        name = NULL;
3528                }
3529
3530                ver_name = mnl_attr_get_str(tb[DEVLINK_ATTR_INFO_VERSION_NAME]);
3531                ver_value = mnl_attr_get_str(tb[DEVLINK_ATTR_INFO_VERSION_VALUE]);
3532
3533                check_indent_newline(dl);
3534                print_string_name_value(ver_name, ver_value);
3535                if (!dl->json_output)
3536                        __pr_out_newline();
3537        }
3538
3539        if (!name)
3540                pr_out_object_end(dl);
3541}
3542
3543static void pr_out_info(struct dl *dl, const struct nlmsghdr *nlh,
3544                        struct nlattr **tb, bool has_versions)
3545{
3546        __pr_out_handle_start(dl, tb, true, false);
3547
3548        __pr_out_indent_inc();
3549        if (tb[DEVLINK_ATTR_INFO_DRIVER_NAME]) {
3550                struct nlattr *nla_drv = tb[DEVLINK_ATTR_INFO_DRIVER_NAME];
3551
3552                if (!dl->json_output)
3553                        __pr_out_newline();
3554                check_indent_newline(dl);
3555                print_string(PRINT_ANY, "driver", "driver %s",
3556                             mnl_attr_get_str(nla_drv));
3557        }
3558
3559        if (tb[DEVLINK_ATTR_INFO_SERIAL_NUMBER]) {
3560                struct nlattr *nla_sn = tb[DEVLINK_ATTR_INFO_SERIAL_NUMBER];
3561
3562                if (!dl->json_output)
3563                        __pr_out_newline();
3564                check_indent_newline(dl);
3565                print_string(PRINT_ANY, "serial_number", "serial_number %s",
3566                             mnl_attr_get_str(nla_sn));
3567        }
3568
3569        if (tb[DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER]) {
3570                struct nlattr *nla_bsn = tb[DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER];
3571
3572                if (!dl->json_output)
3573                        __pr_out_newline();
3574                check_indent_newline(dl);
3575                print_string(PRINT_ANY, "board.serial_number", "board.serial_number %s",
3576                             mnl_attr_get_str(nla_bsn));
3577        }
3578        __pr_out_indent_dec();
3579
3580        if (has_versions) {
3581                pr_out_object_start(dl, "versions");
3582
3583                pr_out_versions_single(dl, nlh, "fixed",
3584                                       DEVLINK_ATTR_INFO_VERSION_FIXED);
3585                pr_out_versions_single(dl, nlh, "running",
3586                                       DEVLINK_ATTR_INFO_VERSION_RUNNING);
3587                pr_out_versions_single(dl, nlh, "stored",
3588                                       DEVLINK_ATTR_INFO_VERSION_STORED);
3589
3590                pr_out_object_end(dl);
3591        }
3592
3593        pr_out_handle_end(dl);
3594}
3595
3596static int cmd_versions_show_cb(const struct nlmsghdr *nlh, void *data)
3597{
3598        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3599        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3600        bool has_versions, has_info;
3601        struct dl *dl = data;
3602
3603        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3604
3605        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
3606                return MNL_CB_ERROR;
3607
3608        has_versions = tb[DEVLINK_ATTR_INFO_VERSION_FIXED] ||
3609                tb[DEVLINK_ATTR_INFO_VERSION_RUNNING] ||
3610                tb[DEVLINK_ATTR_INFO_VERSION_STORED];
3611        has_info = tb[DEVLINK_ATTR_INFO_DRIVER_NAME] ||
3612                tb[DEVLINK_ATTR_INFO_SERIAL_NUMBER] ||
3613                tb[DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER] ||
3614                has_versions;
3615
3616        if (has_info)
3617                pr_out_info(dl, nlh, tb, has_versions);
3618
3619        return MNL_CB_OK;
3620}
3621
3622static int cmd_dev_info(struct dl *dl)
3623{
3624        struct nlmsghdr *nlh;
3625        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
3626        int err;
3627
3628        if (dl_argv_match(dl, "help")) {
3629                cmd_dev_help();
3630                return 0;
3631        }
3632
3633        if (dl_argc(dl) == 0)
3634                flags |= NLM_F_DUMP;
3635
3636        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_INFO_GET, flags);
3637
3638        if (dl_argc(dl) > 0) {
3639                err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
3640                if (err)
3641                        return err;
3642        }
3643
3644        pr_out_section_start(dl, "info");
3645        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_versions_show_cb, dl);
3646        pr_out_section_end(dl);
3647        return err;
3648}
3649
3650struct cmd_dev_flash_status_ctx {
3651        struct dl *dl;
3652        struct timespec time_of_last_status;
3653        uint64_t status_msg_timeout;
3654        size_t elapsed_time_msg_len;
3655        char *last_msg;
3656        char *last_component;
3657        uint8_t not_first:1,
3658                last_pc:1,
3659                received_end:1,
3660                flash_done:1;
3661};
3662
3663static int nullstrcmp(const char *str1, const char *str2)
3664{
3665        if (str1 && str2)
3666                return strcmp(str1, str2);
3667        if (!str1 && !str2)
3668                return 0;
3669        return str1 ? 1 : -1;
3670}
3671
3672static void cmd_dev_flash_clear_elapsed_time(struct cmd_dev_flash_status_ctx *ctx)
3673{
3674        int i;
3675
3676        for (i = 0; i < ctx->elapsed_time_msg_len; i++)
3677                pr_out_tty("\b \b");
3678
3679        ctx->elapsed_time_msg_len = 0;
3680}
3681
3682static int cmd_dev_flash_status_cb(const struct nlmsghdr *nlh, void *data)
3683{
3684        struct cmd_dev_flash_status_ctx *ctx = data;
3685        struct dl_opts *opts = &ctx->dl->opts;
3686        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3687        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3688        const char *component = NULL;
3689        uint64_t done = 0, total = 0;
3690        const char *msg = NULL;
3691        const char *bus_name;
3692        const char *dev_name;
3693
3694        cmd_dev_flash_clear_elapsed_time(ctx);
3695
3696        if (genl->cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS &&
3697            genl->cmd != DEVLINK_CMD_FLASH_UPDATE_END)
3698                return MNL_CB_STOP;
3699
3700        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3701        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
3702                return MNL_CB_ERROR;
3703        bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
3704        dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
3705        if (strcmp(bus_name, opts->bus_name) ||
3706            strcmp(dev_name, opts->dev_name))
3707                return MNL_CB_ERROR;
3708
3709        if (genl->cmd == DEVLINK_CMD_FLASH_UPDATE_END) {
3710                pr_out("\n");
3711                free(ctx->last_msg);
3712                free(ctx->last_component);
3713                ctx->received_end = 1;
3714                return MNL_CB_STOP;
3715        }
3716
3717        if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG])
3718                msg = mnl_attr_get_str(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG]);
3719        if (tb[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT])
3720                component = mnl_attr_get_str(tb[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT]);
3721        if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE])
3722                done = mnl_attr_get_u64(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE]);
3723        if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL])
3724                total = mnl_attr_get_u64(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL]);
3725        if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TIMEOUT])
3726                ctx->status_msg_timeout = mnl_attr_get_u64(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TIMEOUT]);
3727        else
3728                ctx->status_msg_timeout = 0;
3729
3730        if (!nullstrcmp(msg, ctx->last_msg) &&
3731            !nullstrcmp(component, ctx->last_component) &&
3732            ctx->last_pc && ctx->not_first) {
3733                pr_out_tty("\b\b\b\b\b"); /* clean percentage */
3734        } else {
3735                /* only update the last status timestamp if the message changed */
3736                clock_gettime(CLOCK_MONOTONIC, &ctx->time_of_last_status);
3737
3738                if (ctx->not_first)
3739                        pr_out("\n");
3740                if (component) {
3741                        pr_out("[%s] ", component);
3742                        free(ctx->last_component);
3743                        ctx->last_component = strdup(component);
3744                }
3745                if (msg) {
3746                        pr_out("%s", msg);
3747                        free(ctx->last_msg);
3748                        ctx->last_msg = strdup(msg);
3749                }
3750        }
3751        if (total) {
3752                pr_out_tty(" %3"PRIu64"%%", (done * 100) / total);
3753                ctx->last_pc = 1;
3754        } else {
3755                ctx->last_pc = 0;
3756        }
3757        fflush(stdout);
3758        ctx->not_first = 1;
3759
3760        return MNL_CB_STOP;
3761}
3762
3763static void cmd_dev_flash_time_elapsed(struct cmd_dev_flash_status_ctx *ctx)
3764{
3765        struct timespec now, res;
3766
3767        clock_gettime(CLOCK_MONOTONIC, &now);
3768
3769        res.tv_sec = now.tv_sec - ctx->time_of_last_status.tv_sec;
3770        res.tv_nsec = now.tv_nsec - ctx->time_of_last_status.tv_nsec;
3771        if (res.tv_nsec < 0) {
3772                res.tv_sec--;
3773                res.tv_nsec += 1000000000L;
3774        }
3775
3776        /* Only begin displaying an elapsed time message if we've waited a few
3777         * seconds with no response, or the status message included a timeout
3778         * value.
3779         */
3780        if (res.tv_sec > 2 || ctx->status_msg_timeout) {
3781                uint64_t elapsed_m, elapsed_s;
3782                char msg[128];
3783                size_t len;
3784
3785                /* clear the last elapsed time message, if we have one */
3786                cmd_dev_flash_clear_elapsed_time(ctx);
3787
3788                elapsed_m = res.tv_sec / 60;
3789                elapsed_s = res.tv_sec % 60;
3790
3791                /**
3792                 * If we've elapsed a few seconds without receiving any status
3793                 * notification from the device, we display a time elapsed
3794                 * message. This has a few possible formats:
3795                 *
3796                 * 1) just time elapsed, when no timeout was provided
3797                 *    " ( Xm Ys )"
3798                 * 2) time elapsed out of a timeout that came from the device
3799                 *    driver via DEVLINK_CMD_FLASH_UPDATE_STATUS_TIMEOUT
3800                 *    " ( Xm Ys : Am Ys)"
3801                 * 3) time elapsed if we still receive no status after
3802                 *    reaching the provided timeout.
3803                 *    " ( Xm Ys : timeout reached )"
3804                 */
3805                if (!ctx->status_msg_timeout) {
3806                        len = snprintf(msg, sizeof(msg),
3807                                       " ( %"PRIu64"m %"PRIu64"s )", elapsed_m, elapsed_s);
3808                } else if (res.tv_sec <= ctx->status_msg_timeout) {
3809                        uint64_t timeout_m, timeout_s;
3810
3811                        timeout_m = ctx->status_msg_timeout / 60;
3812                        timeout_s = ctx->status_msg_timeout % 60;
3813
3814                        len = snprintf(msg, sizeof(msg),
3815                                       " ( %"PRIu64"m %"PRIu64"s : %"PRIu64"m %"PRIu64"s )",
3816                                       elapsed_m, elapsed_s, timeout_m, timeout_s);
3817                } else {
3818                        len = snprintf(msg, sizeof(msg),
3819                                       " ( %"PRIu64"m %"PRIu64"s : timeout reached )", elapsed_m, elapsed_s);
3820                }
3821
3822                ctx->elapsed_time_msg_len = len;
3823
3824                pr_out_tty("%s", msg);
3825                fflush(stdout);
3826        }
3827}
3828
3829static int cmd_dev_flash_fds_process(struct cmd_dev_flash_status_ctx *ctx,
3830                                     struct mnlu_gen_socket *nlg_ntf,
3831                                     int pipe_r)
3832{
3833        int nlfd = mnlg_socket_get_fd(nlg_ntf);
3834        struct timeval timeout;
3835        fd_set fds[3];
3836        int fdmax;
3837        int i;
3838        int err;
3839        int err2;
3840
3841        for (i = 0; i < 3; i++)
3842                FD_ZERO(&fds[i]);
3843        FD_SET(pipe_r, &fds[0]);
3844        fdmax = pipe_r + 1;
3845        FD_SET(nlfd, &fds[0]);
3846        if (nlfd >= fdmax)
3847                fdmax = nlfd + 1;
3848
3849        /* select only for a short while (1/10th of a second) in order to
3850         * allow periodically updating the screen with an elapsed time
3851         * indicator.
3852         */
3853        timeout.tv_sec = 0;
3854        timeout.tv_usec = 100000;
3855
3856        while (select(fdmax, &fds[0], &fds[1], &fds[2], &timeout) < 0) {
3857                if (errno == EINTR)
3858                        continue;
3859                pr_err("select() failed\n");
3860                return -errno;
3861        }
3862        if (FD_ISSET(nlfd, &fds[0])) {
3863                err = mnlu_gen_socket_recv_run(nlg_ntf,
3864                                               cmd_dev_flash_status_cb, ctx);
3865                if (err)
3866                        return err;
3867        }
3868        if (FD_ISSET(pipe_r, &fds[0])) {
3869                err = read(pipe_r, &err2, sizeof(err2));
3870                if (err == -1) {
3871                        pr_err("Failed to read pipe\n");
3872                        return -errno;
3873                }
3874                if (err2)
3875                        return err2;
3876                ctx->flash_done = 1;
3877        }
3878        cmd_dev_flash_time_elapsed(ctx);
3879        return 0;
3880}
3881
3882
3883static int cmd_dev_flash(struct dl *dl)
3884{
3885        struct cmd_dev_flash_status_ctx ctx = {.dl = dl,};
3886        struct mnlu_gen_socket nlg_ntf;
3887        struct nlmsghdr *nlh;
3888        int pipe_r, pipe_w;
3889        int pipe_fds[2];
3890        pid_t pid;
3891        int err;
3892
3893        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
3894                cmd_dev_help();
3895                return 0;
3896        }
3897
3898        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_FLASH_UPDATE,
3899                               NLM_F_REQUEST | NLM_F_ACK);
3900
3901        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_FLASH_FILE_NAME,
3902                                DL_OPT_FLASH_COMPONENT | DL_OPT_FLASH_OVERWRITE);
3903        if (err)
3904                return err;
3905
3906        err = mnlu_gen_socket_open(&nlg_ntf, DEVLINK_GENL_NAME,
3907                                   DEVLINK_GENL_VERSION);
3908        if (err)
3909                return err;
3910
3911        err = _mnlg_socket_group_add(&nlg_ntf, DEVLINK_GENL_MCGRP_CONFIG_NAME);
3912        if (err)
3913                goto err_socket;
3914
3915        err = pipe(pipe_fds);
3916        if (err == -1) {
3917                err = -errno;
3918                goto err_socket;
3919        }
3920        pipe_r = pipe_fds[0];
3921        pipe_w = pipe_fds[1];
3922
3923        pid = fork();
3924        if (pid == -1) {
3925                close(pipe_w);
3926                err = -errno;
3927                goto out;
3928        } else if (!pid) {
3929                /* In child, just execute the flash and pass returned
3930                 * value through pipe once it is done.
3931                 */
3932                int cc;
3933
3934                close(pipe_r);
3935                err = _mnlg_socket_send(&dl->nlg, nlh);
3936                cc = write(pipe_w, &err, sizeof(err));
3937                close(pipe_w);
3938                exit(cc != sizeof(err));
3939        }
3940        close(pipe_w);
3941
3942        /* initialize starting time to allow comparison for when to begin
3943         * displaying a time elapsed message.
3944         */
3945        clock_gettime(CLOCK_MONOTONIC, &ctx.time_of_last_status);
3946
3947        do {
3948                err = cmd_dev_flash_fds_process(&ctx, &nlg_ntf, pipe_r);
3949                if (err)
3950                        goto out;
3951        } while (!ctx.flash_done || (ctx.not_first && !ctx.received_end));
3952
3953        err = mnlu_gen_socket_recv_run(&dl->nlg, NULL, NULL);
3954
3955out:
3956        close(pipe_r);
3957err_socket:
3958        mnlu_gen_socket_close(&nlg_ntf);
3959        return err;
3960}
3961
3962static int cmd_dev(struct dl *dl)
3963{
3964        if (dl_argv_match(dl, "help")) {
3965                cmd_dev_help();
3966                return 0;
3967        } else if (dl_argv_match(dl, "show") ||
3968                   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
3969                dl_arg_inc(dl);
3970                return cmd_dev_show(dl);
3971        } else if (dl_argv_match(dl, "eswitch")) {
3972                dl_arg_inc(dl);
3973                return cmd_dev_eswitch(dl);
3974        } else if (dl_argv_match(dl, "reload")) {
3975                dl_arg_inc(dl);
3976                return cmd_dev_reload(dl);
3977        } else if (dl_argv_match(dl, "param")) {
3978                dl_arg_inc(dl);
3979                return cmd_dev_param(dl);
3980        } else if (dl_argv_match(dl, "info")) {
3981                dl_arg_inc(dl);
3982                return cmd_dev_info(dl);
3983        } else if (dl_argv_match(dl, "flash")) {
3984                dl_arg_inc(dl);
3985                return cmd_dev_flash(dl);
3986        }
3987        pr_err("Command \"%s\" not found\n", dl_argv(dl));
3988        return -ENOENT;
3989}
3990
3991static void cmd_port_help(void)
3992{
3993        pr_err("Usage: devlink port show [ DEV/PORT_INDEX ]\n");
3994        pr_err("       devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n");
3995        pr_err("       devlink port split DEV/PORT_INDEX count COUNT\n");
3996        pr_err("       devlink port unsplit DEV/PORT_INDEX\n");
3997        pr_err("       devlink port function set DEV/PORT_INDEX [ hw_addr ADDR ] [ state { active | inactive } ]\n");
3998        pr_err("       devlink port function rate { help | show | add | del | set }\n");
3999        pr_err("       devlink port param set DEV/PORT_INDEX name PARAMETER value VALUE cmode { permanent | driverinit | runtime }\n");
4000        pr_err("       devlink port param show [DEV/PORT_INDEX name PARAMETER]\n");
4001        pr_err("       devlink port health show [ DEV/PORT_INDEX reporter REPORTER_NAME ]\n");
4002        pr_err("       devlink port add DEV/PORT_INDEX flavour FLAVOUR pfnum PFNUM\n"
4003               "                      [ sfnum SFNUM ][ controller CNUM ]\n");
4004        pr_err("       devlink port del DEV/PORT_INDEX\n");
4005}
4006
4007static const char *port_type_name(uint32_t type)
4008{
4009        switch (type) {
4010        case DEVLINK_PORT_TYPE_NOTSET: return "notset";
4011        case DEVLINK_PORT_TYPE_AUTO: return "auto";
4012        case DEVLINK_PORT_TYPE_ETH: return "eth";
4013        case DEVLINK_PORT_TYPE_IB: return "ib";
4014        default: return "<unknown type>";
4015        }
4016}
4017
4018static const char *port_flavour_name(uint16_t flavour)
4019{
4020        const char *str;
4021
4022        str = str_map_lookup_u16(port_flavour_map, flavour);
4023        return str ? str : "<unknown flavour>";
4024}
4025
4026static void pr_out_port_pfvfsf_num(struct dl *dl, struct nlattr **tb)
4027{
4028        uint16_t fn_num;
4029
4030        if (tb[DEVLINK_ATTR_PORT_CONTROLLER_NUMBER])
4031                print_uint(PRINT_ANY, "controller", " controller %u",
4032                           mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_CONTROLLER_NUMBER]));
4033        if (tb[DEVLINK_ATTR_PORT_PCI_PF_NUMBER]) {
4034                fn_num = mnl_attr_get_u16(tb[DEVLINK_ATTR_PORT_PCI_PF_NUMBER]);
4035                print_uint(PRINT_ANY, "pfnum", " pfnum %u", fn_num);
4036        }
4037        if (tb[DEVLINK_ATTR_PORT_PCI_VF_NUMBER]) {
4038                fn_num = mnl_attr_get_u16(tb[DEVLINK_ATTR_PORT_PCI_VF_NUMBER]);
4039                print_uint(PRINT_ANY, "vfnum", " vfnum %u", fn_num);
4040        }
4041        if (tb[DEVLINK_ATTR_PORT_PCI_SF_NUMBER]) {
4042                fn_num = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_PCI_SF_NUMBER]);
4043                print_uint(PRINT_ANY, "sfnum", " sfnum %u", fn_num);
4044        }
4045        if (tb[DEVLINK_ATTR_PORT_EXTERNAL]) {
4046                uint8_t external;
4047
4048                external = mnl_attr_get_u8(tb[DEVLINK_ATTR_PORT_EXTERNAL]);
4049                print_bool(PRINT_ANY, "external", " external %s", external);
4050        }
4051}
4052
4053static const char *port_fn_state(uint8_t state)
4054{
4055        const char *str;
4056
4057        str = str_map_lookup_u8(port_fn_state_map, state);
4058        return str ? str : "<unknown state>";
4059}
4060
4061static const char *port_fn_opstate(uint8_t state)
4062{
4063        const char *str;
4064
4065        str = str_map_lookup_u8(port_fn_opstate_map, state);
4066        return str ? str : "<unknown state>";
4067}
4068
4069static void pr_out_port_function(struct dl *dl, struct nlattr **tb_port)
4070{
4071        struct nlattr *tb[DEVLINK_PORT_FUNCTION_ATTR_MAX + 1] = {};
4072        unsigned char *data;
4073        SPRINT_BUF(hw_addr);
4074        uint32_t len;
4075        int err;
4076
4077        if (!tb_port[DEVLINK_ATTR_PORT_FUNCTION])
4078                return;
4079
4080        err = mnl_attr_parse_nested(tb_port[DEVLINK_ATTR_PORT_FUNCTION],
4081                                    function_attr_cb, tb);
4082        if (err != MNL_CB_OK)
4083                return;
4084
4085        pr_out_object_start(dl, "function");
4086        check_indent_newline(dl);
4087
4088        if (tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR]) {
4089                len = mnl_attr_get_payload_len(tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR]);
4090                data = mnl_attr_get_payload(tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR]);
4091
4092                print_string(PRINT_ANY, "hw_addr", "hw_addr %s",
4093                             ll_addr_n2a(data, len, 0, hw_addr, sizeof(hw_addr)));
4094        }
4095        if (tb[DEVLINK_PORT_FN_ATTR_STATE]) {
4096                uint8_t state;
4097
4098                state = mnl_attr_get_u8(tb[DEVLINK_PORT_FN_ATTR_STATE]);
4099
4100                print_string(PRINT_ANY, "state", " state %s",
4101                             port_fn_state(state));
4102        }
4103        if (tb[DEVLINK_PORT_FN_ATTR_OPSTATE]) {
4104                uint8_t state;
4105
4106                state = mnl_attr_get_u8(tb[DEVLINK_PORT_FN_ATTR_OPSTATE]);
4107
4108                print_string(PRINT_ANY, "opstate", " opstate %s",
4109                             port_fn_opstate(state));
4110        }
4111
4112        if (!dl->json_output)
4113                __pr_out_indent_dec();
4114        pr_out_object_end(dl);
4115}
4116
4117static void pr_out_port(struct dl *dl, struct nlattr **tb)
4118{
4119        struct nlattr *pt_attr = tb[DEVLINK_ATTR_PORT_TYPE];
4120        struct nlattr *dpt_attr = tb[DEVLINK_ATTR_PORT_DESIRED_TYPE];
4121
4122        pr_out_port_handle_start(dl, tb, false);
4123        check_indent_newline(dl);
4124        if (pt_attr) {
4125                uint16_t port_type = mnl_attr_get_u16(pt_attr);
4126
4127                print_string(PRINT_ANY, "type", "type %s",
4128                             port_type_name(port_type));
4129                if (dpt_attr) {
4130                        uint16_t des_port_type = mnl_attr_get_u16(dpt_attr);
4131
4132                        if (port_type != des_port_type)
4133                                print_string(PRINT_ANY, "des_type", " des_type %s",
4134                                             port_type_name(des_port_type));
4135                }
4136        }
4137        if (tb[DEVLINK_ATTR_PORT_NETDEV_NAME]) {
4138                print_string(PRINT_ANY, "netdev", " netdev %s",
4139                             mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME]));
4140        }
4141        if (tb[DEVLINK_ATTR_PORT_IBDEV_NAME]) {
4142                print_string(PRINT_ANY, "ibdev", " ibdev %s",
4143                             mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_IBDEV_NAME]));
4144                }
4145        if (tb[DEVLINK_ATTR_PORT_FLAVOUR]) {
4146                uint16_t port_flavour =
4147                                mnl_attr_get_u16(tb[DEVLINK_ATTR_PORT_FLAVOUR]);
4148
4149                print_string(PRINT_ANY, "flavour", " flavour %s",
4150                             port_flavour_name(port_flavour));
4151
4152                switch (port_flavour) {
4153                case DEVLINK_PORT_FLAVOUR_PCI_PF:
4154                case DEVLINK_PORT_FLAVOUR_PCI_VF:
4155                case DEVLINK_PORT_FLAVOUR_PCI_SF:
4156                        pr_out_port_pfvfsf_num(dl, tb);
4157                        break;
4158                default:
4159                        break;
4160                }
4161        }
4162        if (tb[DEVLINK_ATTR_PORT_NUMBER]) {
4163                uint32_t port_number;
4164
4165                port_number = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_NUMBER]);
4166                print_uint(PRINT_ANY, "port", " port %u", port_number);
4167        }
4168        if (tb[DEVLINK_ATTR_PORT_SPLIT_GROUP])
4169                print_uint(PRINT_ANY, "split_group", " split_group %u",
4170                           mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_SPLIT_GROUP]));
4171        if (tb[DEVLINK_ATTR_PORT_SPLITTABLE])
4172                print_bool(PRINT_ANY, "splittable", " splittable %s",
4173                           mnl_attr_get_u8(tb[DEVLINK_ATTR_PORT_SPLITTABLE]));
4174        if (tb[DEVLINK_ATTR_PORT_LANES])
4175                print_uint(PRINT_ANY, "lanes", " lanes %u",
4176                           mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_LANES]));
4177
4178        pr_out_port_function(dl, tb);
4179        pr_out_port_handle_end(dl);
4180}
4181
4182static int cmd_port_show_cb(const struct nlmsghdr *nlh, void *data)
4183{
4184        struct dl *dl = data;
4185        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4186        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4187
4188        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4189        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4190            !tb[DEVLINK_ATTR_PORT_INDEX])
4191                return MNL_CB_ERROR;
4192        pr_out_port(dl, tb);
4193        return MNL_CB_OK;
4194}
4195
4196static int cmd_port_show(struct dl *dl)
4197{
4198        struct nlmsghdr *nlh;
4199        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
4200        int err;
4201
4202        if (dl_argc(dl) == 0)
4203                flags |= NLM_F_DUMP;
4204
4205        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_GET, flags);
4206
4207        if (dl_argc(dl) > 0) {
4208                err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
4209                if (err)
4210                        return err;
4211        }
4212
4213        pr_out_section_start(dl, "port");
4214        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_port_show_cb, dl);
4215        pr_out_section_end(dl);
4216        return err;
4217}
4218
4219static int cmd_port_set(struct dl *dl)
4220{
4221        struct nlmsghdr *nlh;
4222        int err;
4223
4224        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_SET,
4225                               NLM_F_REQUEST | NLM_F_ACK);
4226
4227        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_TYPE, 0);
4228        if (err)
4229                return err;
4230
4231        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
4232}
4233
4234static int cmd_port_split(struct dl *dl)
4235{
4236        struct nlmsghdr *nlh;
4237        int err;
4238
4239        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_SPLIT,
4240                               NLM_F_REQUEST | NLM_F_ACK);
4241
4242        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_COUNT, 0);
4243        if (err)
4244                return err;
4245
4246        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
4247}
4248
4249static int cmd_port_unsplit(struct dl *dl)
4250{
4251        struct nlmsghdr *nlh;
4252        int err;
4253
4254        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_UNSPLIT,
4255                               NLM_F_REQUEST | NLM_F_ACK);
4256
4257        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
4258        if (err)
4259                return err;
4260
4261        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
4262}
4263
4264static int cmd_port_param_show(struct dl *dl)
4265{
4266        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
4267        struct nlmsghdr *nlh;
4268        int err;
4269
4270        if (dl_argc(dl) == 0)
4271                flags |= NLM_F_DUMP;
4272
4273        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_PARAM_GET,
4274                                          flags);
4275
4276        if (dl_argc(dl) > 0) {
4277                err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP |
4278                                        DL_OPT_PARAM_NAME, 0);
4279                if (err)
4280                        return err;
4281        }
4282
4283        pr_out_section_start(dl, "param");
4284        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_port_param_show_cb, dl);
4285        pr_out_section_end(dl);
4286
4287        return err;
4288}
4289
4290static void cmd_port_function_help(void)
4291{
4292        pr_err("Usage: devlink port function set DEV/PORT_INDEX [ hw_addr ADDR ] [ state STATE ]\n");
4293        pr_err("       devlink port function rate { help | show | add | del | set }\n");
4294}
4295
4296static int cmd_port_function_set(struct dl *dl)
4297{
4298        struct nlmsghdr *nlh;
4299        int err;
4300
4301        if (dl_no_arg(dl)) {
4302                cmd_port_function_help();
4303                return 0;
4304        }
4305        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_SET,
4306                                          NLM_F_REQUEST | NLM_F_ACK);
4307
4308        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP,
4309                                DL_OPT_PORT_FUNCTION_HW_ADDR | DL_OPT_PORT_FUNCTION_STATE);
4310        if (err)
4311                return err;
4312
4313        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
4314}
4315
4316static int cmd_port_param_set_cb(const struct nlmsghdr *nlh, void *data)
4317{
4318        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4319        struct nlattr *nla_param[DEVLINK_ATTR_MAX + 1] = {};
4320        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4321        struct nlattr *param_value_attr;
4322        enum devlink_param_cmode cmode;
4323        struct param_ctx *ctx = data;
4324        struct dl *dl = ctx->dl;
4325        int nla_type;
4326        int err;
4327
4328        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4329        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4330            !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_PARAM])
4331                return MNL_CB_ERROR;
4332
4333        err = mnl_attr_parse_nested(tb[DEVLINK_ATTR_PARAM], attr_cb, nla_param);
4334        if (err != MNL_CB_OK)
4335                return MNL_CB_ERROR;
4336
4337        if (!nla_param[DEVLINK_ATTR_PARAM_TYPE] ||
4338            !nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST])
4339                return MNL_CB_ERROR;
4340
4341        nla_type = mnl_attr_get_u8(nla_param[DEVLINK_ATTR_PARAM_TYPE]);
4342        mnl_attr_for_each_nested(param_value_attr,
4343                                 nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST]) {
4344                struct nlattr *nla_value[DEVLINK_ATTR_MAX + 1] = {};
4345                struct nlattr *val_attr;
4346
4347                err = mnl_attr_parse_nested(param_value_attr,
4348                                            attr_cb, nla_value);
4349                if (err != MNL_CB_OK)
4350                        return MNL_CB_ERROR;
4351
4352                if (!nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE] ||
4353                    (nla_type != MNL_TYPE_FLAG &&
4354                     !nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA]))
4355                        return MNL_CB_ERROR;
4356
4357                cmode = mnl_attr_get_u8(nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
4358                if (cmode == dl->opts.cmode) {
4359                        val_attr = nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA];
4360                        switch (nla_type) {
4361                        case MNL_TYPE_U8:
4362                                ctx->value.vu8 = mnl_attr_get_u8(val_attr);
4363                                break;
4364                        case MNL_TYPE_U16:
4365                                ctx->value.vu16 = mnl_attr_get_u16(val_attr);
4366                                break;
4367                        case MNL_TYPE_U32:
4368                                ctx->value.vu32 = mnl_attr_get_u32(val_attr);
4369                                break;
4370                        case MNL_TYPE_STRING:
4371                                ctx->value.vstr = mnl_attr_get_str(val_attr);
4372                                break;
4373                        case MNL_TYPE_FLAG:
4374                                ctx->value.vbool = val_attr ? true : false;
4375                                break;
4376                        }
4377                        break;
4378                }
4379        }
4380        ctx->nla_type = nla_type;
4381        return MNL_CB_OK;
4382}
4383
4384static int cmd_port_param_set(struct dl *dl)
4385{
4386        struct param_ctx ctx = {};
4387        struct nlmsghdr *nlh;
4388        bool conv_exists;
4389        uint32_t val_u32 = 0;
4390        uint16_t val_u16;
4391        uint8_t val_u8;
4392        bool val_bool;
4393        int err;
4394
4395        err = dl_argv_parse(dl, DL_OPT_HANDLEP |
4396                            DL_OPT_PARAM_NAME |
4397                            DL_OPT_PARAM_VALUE |
4398                            DL_OPT_PARAM_CMODE, 0);
4399        if (err)
4400                return err;
4401
4402        /* Get value type */
4403        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_PARAM_GET,
4404                                          NLM_F_REQUEST | NLM_F_ACK);
4405        dl_opts_put(nlh, dl);
4406
4407        ctx.dl = dl;
4408        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_port_param_set_cb, &ctx);
4409        if (err)
4410                return err;
4411
4412        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_PARAM_SET,
4413                                          NLM_F_REQUEST | NLM_F_ACK);
4414        dl_opts_put(nlh, dl);
4415
4416        conv_exists = param_val_conv_exists(param_val_conv, PARAM_VAL_CONV_LEN,
4417                                            dl->opts.param_name);
4418
4419        mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_TYPE, ctx.nla_type);
4420        switch (ctx.nla_type) {
4421        case MNL_TYPE_U8:
4422                if (conv_exists) {
4423                        err = param_val_conv_uint_get(param_val_conv,
4424                                                      PARAM_VAL_CONV_LEN,
4425                                                      dl->opts.param_name,
4426                                                      dl->opts.param_value,
4427                                                      &val_u32);
4428                        val_u8 = val_u32;
4429                } else {
4430                        err = strtouint8_t(dl->opts.param_value, &val_u8);
4431                }
4432                if (err)
4433                        goto err_param_value_parse;
4434                if (val_u8 == ctx.value.vu8)
4435                        return 0;
4436                mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u8);
4437                break;
4438        case MNL_TYPE_U16:
4439                if (conv_exists) {
4440                        err = param_val_conv_uint_get(param_val_conv,
4441                                                      PARAM_VAL_CONV_LEN,
4442                                                      dl->opts.param_name,
4443                                                      dl->opts.param_value,
4444                                                      &val_u32);
4445                        val_u16 = val_u32;
4446                } else {
4447                        err = strtouint16_t(dl->opts.param_value, &val_u16);
4448                }
4449                if (err)
4450                        goto err_param_value_parse;
4451                if (val_u16 == ctx.value.vu16)
4452                        return 0;
4453                mnl_attr_put_u16(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u16);
4454                break;
4455        case MNL_TYPE_U32:
4456                if (conv_exists)
4457                        err = param_val_conv_uint_get(param_val_conv,
4458                                                      PARAM_VAL_CONV_LEN,
4459                                                      dl->opts.param_name,
4460                                                      dl->opts.param_value,
4461                                                      &val_u32);
4462                else
4463                        err = strtouint32_t(dl->opts.param_value, &val_u32);
4464                if (err)
4465                        goto err_param_value_parse;
4466                if (val_u32 == ctx.value.vu32)
4467                        return 0;
4468                mnl_attr_put_u32(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u32);
4469                break;
4470        case MNL_TYPE_FLAG:
4471                err = strtobool(dl->opts.param_value, &val_bool);
4472                if (err)
4473                        goto err_param_value_parse;
4474                if (val_bool == ctx.value.vbool)
4475                        return 0;
4476                if (val_bool)
4477                        mnl_attr_put(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA,
4478                                     0, NULL);
4479                break;
4480        case MNL_TYPE_STRING:
4481                mnl_attr_put_strz(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA,
4482                                  dl->opts.param_value);
4483                if (!strcmp(dl->opts.param_value, ctx.value.vstr))
4484                        return 0;
4485                break;
4486        default:
4487                printf("Value type not supported\n");
4488                return -ENOTSUP;
4489        }
4490        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
4491
4492err_param_value_parse:
4493        pr_err("Value \"%s\" is not a number or not within range\n",
4494               dl->opts.param_value);
4495        return err;
4496}
4497
4498static int cmd_port_param(struct dl *dl)
4499{
4500        if (dl_argv_match(dl, "help")) {
4501                cmd_port_help();
4502                return 0;
4503        } else if (dl_argv_match(dl, "show") ||
4504                   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
4505                dl_arg_inc(dl);
4506                return cmd_port_param_show(dl);
4507        } else if (dl_argv_match(dl, "set")) {
4508                dl_arg_inc(dl);
4509                return cmd_port_param_set(dl);
4510        }
4511        pr_err("Command \"%s\" not found\n", dl_argv(dl));
4512        return -ENOENT;
4513}
4514
4515static void
4516pr_out_port_rate_handle_start(struct dl *dl, struct nlattr **tb, bool try_nice)
4517{
4518        const char *bus_name;
4519        const char *dev_name;
4520        const char *node_name;
4521        static char buf[64];
4522
4523        bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
4524        dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
4525        node_name = mnl_attr_get_str(tb[DEVLINK_ATTR_RATE_NODE_NAME]);
4526        sprintf(buf, "%s/%s/%s", bus_name, dev_name, node_name);
4527        if (dl->json_output)
4528                open_json_object(buf);
4529        else
4530                pr_out("%s:", buf);
4531}
4532
4533static char *port_rate_type_name(uint16_t type)
4534{
4535        switch (type) {
4536        case DEVLINK_RATE_TYPE_LEAF:
4537                return "leaf";
4538        case DEVLINK_RATE_TYPE_NODE:
4539                return "node";
4540        default:
4541                return "<unknown type>";
4542        }
4543}
4544
4545static void pr_out_port_fn_rate(struct dl *dl, struct nlattr **tb)
4546{
4547
4548        if (!tb[DEVLINK_ATTR_RATE_NODE_NAME])
4549                pr_out_port_handle_start(dl, tb, false);
4550        else
4551                pr_out_port_rate_handle_start(dl, tb, false);
4552        check_indent_newline(dl);
4553
4554        if (tb[DEVLINK_ATTR_RATE_TYPE]) {
4555                uint16_t type =
4556                        mnl_attr_get_u16(tb[DEVLINK_ATTR_RATE_TYPE]);
4557
4558                print_string(PRINT_ANY, "type", "type %s",
4559                                port_rate_type_name(type));
4560        }
4561        if (tb[DEVLINK_ATTR_RATE_TX_SHARE]) {
4562                uint64_t rate =
4563                        mnl_attr_get_u64(tb[DEVLINK_ATTR_RATE_TX_SHARE]);
4564
4565                if (rate)
4566                        print_rate(use_iec, PRINT_ANY, "tx_share",
4567                                   " tx_share %s", rate);
4568        }
4569        if (tb[DEVLINK_ATTR_RATE_TX_MAX]) {
4570                uint64_t rate =
4571                        mnl_attr_get_u64(tb[DEVLINK_ATTR_RATE_TX_MAX]);
4572
4573                if (rate)
4574                        print_rate(use_iec, PRINT_ANY, "tx_max",
4575                                   " tx_max %s", rate);
4576        }
4577        if (tb[DEVLINK_ATTR_RATE_PARENT_NODE_NAME]) {
4578                const char *parent =
4579                        mnl_attr_get_str(tb[DEVLINK_ATTR_RATE_PARENT_NODE_NAME]);
4580
4581                print_string(PRINT_ANY, "parent", " parent %s", parent);
4582        }
4583
4584        pr_out_port_handle_end(dl);
4585}
4586
4587static int cmd_port_fn_rate_show_cb(const struct nlmsghdr *nlh, void *data)
4588{
4589        struct dl *dl = data;
4590        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4591        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4592
4593        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4594        if ((!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4595             !tb[DEVLINK_ATTR_PORT_INDEX]) &&
4596            !tb[DEVLINK_ATTR_RATE_NODE_NAME]) {
4597                return MNL_CB_ERROR;
4598        }
4599        pr_out_port_fn_rate(dl, tb);
4600        return MNL_CB_OK;
4601}
4602
4603static void cmd_port_fn_rate_help(void)
4604{
4605        pr_err("Usage: devlink port function rate help\n");
4606        pr_err("       devlink port function rate show [ DEV/{ PORT_INDEX | NODE_NAME } ]\n");
4607        pr_err("       devlink port function rate add DEV/NODE_NAME\n");
4608        pr_err("               [ tx_share VAL ][ tx_max VAL ][ { parent NODE_NAME | noparent } ]\n");
4609        pr_err("       devlink port function rate del DEV/NODE_NAME\n");
4610        pr_err("       devlink port function rate set DEV/{ PORT_INDEX | NODE_NAME }\n");
4611        pr_err("               [ tx_share VAL ][ tx_max VAL ][ { parent NODE_NAME | noparent } ]\n\n");
4612        pr_err("       VAL - float or integer value in units of bits or bytes per second (bit|bps)\n");
4613        pr_err("       and SI (k-, m-, g-, t-) or IEC (ki-, mi-, gi-, ti-) case-insensitive prefix.\n");
4614        pr_err("       Bare number, means bits per second, is possible.\n\n");
4615        pr_err("       For details refer to devlink-rate(8) man page.\n");
4616}
4617
4618static int cmd_port_fn_rate_show(struct dl *dl)
4619{
4620        struct nlmsghdr *nlh;
4621        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
4622        int err;
4623
4624        if (dl_argc(dl) == 0)
4625                flags |= NLM_F_DUMP;
4626
4627        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RATE_GET, flags);
4628
4629        if (dl_argc(dl) > 0) {
4630                err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP |
4631                                        DL_OPT_PORT_FN_RATE_NODE_NAME, 0);
4632                if (err)
4633                        return err;
4634        }
4635
4636        pr_out_section_start(dl, "rate");
4637        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_port_fn_rate_show_cb, dl);
4638        pr_out_section_end(dl);
4639        return err;
4640}
4641
4642static int port_fn_check_tx_rates(uint64_t min_rate, uint64_t max_rate)
4643{
4644        if (max_rate && min_rate > max_rate) {
4645                pr_err("Invalid. Expected tx_share <= tx_max or tx_share == 0.\n");
4646                return -EINVAL;
4647        }
4648        return 0;
4649}
4650
4651static int port_fn_get_and_check_tx_rates(struct dl_opts *reply,
4652                                          struct dl_opts *request)
4653{
4654        uint64_t min = reply->rate_tx_share;
4655        uint64_t max = reply->rate_tx_max;
4656
4657        if (request->present & DL_OPT_PORT_FN_RATE_TX_SHARE)
4658                return port_fn_check_tx_rates(request->rate_tx_share, max);
4659        return port_fn_check_tx_rates(min, request->rate_tx_max);
4660}
4661
4662static int cmd_port_fn_rate_add(struct dl *dl)
4663{
4664        struct nlmsghdr *nlh;
4665        int err;
4666
4667        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RATE_NEW,
4668                                          NLM_F_REQUEST | NLM_F_ACK);
4669        err = dl_argv_parse_put(nlh, dl, DL_OPT_PORT_FN_RATE_NODE_NAME,
4670                                DL_OPT_PORT_FN_RATE_TX_SHARE |
4671                                DL_OPT_PORT_FN_RATE_TX_MAX);
4672        if (err)
4673                return err;
4674
4675        if ((dl->opts.present & DL_OPT_PORT_FN_RATE_TX_SHARE) &&
4676            (dl->opts.present & DL_OPT_PORT_FN_RATE_TX_MAX)) {
4677                err = port_fn_check_tx_rates(dl->opts.rate_tx_share,
4678                                             dl->opts.rate_tx_max);
4679                if (err)
4680                        return err;
4681        }
4682
4683        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
4684}
4685
4686static int cmd_port_fn_rate_del(struct dl *dl)
4687{
4688        struct nlmsghdr *nlh;
4689        int err;
4690
4691        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RATE_DEL,
4692                                          NLM_F_REQUEST | NLM_F_ACK);
4693        err = dl_argv_parse_put(nlh, dl, DL_OPT_PORT_FN_RATE_NODE_NAME, 0);
4694        if (err)
4695                return err;
4696
4697        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
4698}
4699
4700static int port_fn_get_rates_cb(const struct nlmsghdr *nlh, void *data)
4701{
4702        struct dl_opts *opts = data;
4703        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4704        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4705
4706        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4707        if ((!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4708             !tb[DEVLINK_ATTR_PORT_INDEX]) &&
4709            !tb[DEVLINK_ATTR_RATE_NODE_NAME]) {
4710                return MNL_CB_ERROR;
4711        }
4712
4713        if (tb[DEVLINK_ATTR_RATE_TX_SHARE])
4714                opts->rate_tx_share =
4715                        mnl_attr_get_u64(tb[DEVLINK_ATTR_RATE_TX_SHARE]);
4716        if (tb[DEVLINK_ATTR_RATE_TX_MAX])
4717                opts->rate_tx_max =
4718                        mnl_attr_get_u64(tb[DEVLINK_ATTR_RATE_TX_MAX]);
4719        return MNL_CB_OK;
4720}
4721
4722static int cmd_port_fn_rate_set(struct dl *dl)
4723{
4724        struct dl_opts tmp_opts = {0};
4725        struct nlmsghdr *nlh;
4726        int err;
4727
4728        err = dl_argv_parse(dl, DL_OPT_HANDLEP |
4729                                DL_OPT_PORT_FN_RATE_NODE_NAME,
4730                                DL_OPT_PORT_FN_RATE_TX_SHARE |
4731                                DL_OPT_PORT_FN_RATE_TX_MAX |
4732                                DL_OPT_PORT_FN_RATE_PARENT);
4733        if (err)
4734                return err;
4735
4736        if ((dl->opts.present & DL_OPT_PORT_FN_RATE_TX_SHARE) &&
4737            (dl->opts.present & DL_OPT_PORT_FN_RATE_TX_MAX)) {
4738                err = port_fn_check_tx_rates(dl->opts.rate_tx_share,
4739                                             dl->opts.rate_tx_max);
4740                if (err)
4741                        return err;
4742        } else if (dl->opts.present &
4743                   (DL_OPT_PORT_FN_RATE_TX_SHARE | DL_OPT_PORT_FN_RATE_TX_MAX)) {
4744                nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RATE_GET,
4745                                                  NLM_F_REQUEST | NLM_F_ACK);
4746                tmp_opts = dl->opts;
4747                dl->opts.present &= ~(DL_OPT_PORT_FN_RATE_TX_SHARE |
4748                                      DL_OPT_PORT_FN_RATE_TX_MAX |
4749                                      DL_OPT_PORT_FN_RATE_PARENT);
4750                dl_opts_put(nlh, dl);
4751                err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, port_fn_get_rates_cb,
4752                                             &dl->opts);
4753                if (err)
4754                        return err;
4755                err = port_fn_get_and_check_tx_rates(&dl->opts, &tmp_opts);
4756                if (err)
4757                        return err;
4758                dl->opts = tmp_opts;
4759        }
4760
4761        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RATE_SET,
4762                                          NLM_F_REQUEST | NLM_F_ACK);
4763        dl_opts_put(nlh, dl);
4764        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
4765}
4766
4767static int cmd_port_function_rate(struct dl *dl)
4768{
4769        if (dl_argv_match(dl, "help")) {
4770                cmd_port_fn_rate_help();
4771                return 0;
4772        } else if (dl_argv_match(dl, "show") || dl_no_arg(dl)) {
4773                dl_arg_inc(dl);
4774                return cmd_port_fn_rate_show(dl);
4775        } else if (dl_argv_match(dl, "add")) {
4776                dl_arg_inc(dl);
4777                return cmd_port_fn_rate_add(dl);
4778        } else if (dl_argv_match(dl, "del")) {
4779                dl_arg_inc(dl);
4780                return cmd_port_fn_rate_del(dl);
4781        } else if (dl_argv_match(dl, "set")) {
4782                dl_arg_inc(dl);
4783                return cmd_port_fn_rate_set(dl);
4784        }
4785        pr_err("Command \"%s\" not found\n", dl_argv(dl));
4786        return -ENOENT;
4787}
4788
4789static int cmd_port_function(struct dl *dl)
4790{
4791        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
4792                cmd_port_function_help();
4793                return 0;
4794        } else if (dl_argv_match(dl, "set")) {
4795                dl_arg_inc(dl);
4796                return cmd_port_function_set(dl);
4797        } else if (dl_argv_match(dl, "rate")) {
4798                dl_arg_inc(dl);
4799                return cmd_port_function_rate(dl);
4800        }
4801        pr_err("Command \"%s\" not found\n", dl_argv(dl));
4802        return -ENOENT;
4803}
4804
4805static int cmd_health(struct dl *dl);
4806static int __cmd_health_show(struct dl *dl, bool show_device, bool show_port);
4807
4808static void cmd_port_add_help(void)
4809{
4810        pr_err("       devlink port add DEV/PORT_INDEX flavour FLAVOUR pfnum PFNUM\n"
4811               "                      [ sfnum SFNUM ][ controller CNUM ]\n");
4812}
4813
4814static int cmd_port_add(struct dl *dl)
4815{
4816        struct nlmsghdr *nlh;
4817        int err;
4818
4819        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
4820                cmd_port_add_help();
4821                return 0;
4822        }
4823
4824        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_NEW,
4825                                          NLM_F_REQUEST | NLM_F_ACK);
4826
4827        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_HANDLEP |
4828                                DL_OPT_PORT_FLAVOUR | DL_OPT_PORT_PFNUMBER,
4829                                DL_OPT_PORT_SFNUMBER | DL_OPT_PORT_CONTROLLER);
4830        if (err)
4831                return err;
4832
4833        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_port_show_cb, dl);
4834}
4835
4836static void cmd_port_del_help(void)
4837{
4838        pr_err("       devlink port del DEV/PORT_INDEX\n");
4839}
4840
4841static int cmd_port_del(struct dl *dl)
4842{
4843        struct nlmsghdr *nlh;
4844        int err;
4845
4846        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
4847                cmd_port_del_help();
4848                return 0;
4849        }
4850
4851        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_DEL,
4852                                          NLM_F_REQUEST | NLM_F_ACK);
4853
4854        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
4855        if (err)
4856                return err;
4857
4858        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
4859}
4860
4861static int cmd_port(struct dl *dl)
4862{
4863        if (dl_argv_match(dl, "help")) {
4864                cmd_port_help();
4865                return 0;
4866        } else if (dl_argv_match(dl, "show") ||
4867                   dl_argv_match(dl, "list") ||  dl_no_arg(dl)) {
4868                dl_arg_inc(dl);
4869                return cmd_port_show(dl);
4870        } else if (dl_argv_match(dl, "set")) {
4871                dl_arg_inc(dl);
4872                return cmd_port_set(dl);
4873        } else if (dl_argv_match(dl, "split")) {
4874                dl_arg_inc(dl);
4875                return cmd_port_split(dl);
4876        } else if (dl_argv_match(dl, "unsplit")) {
4877                dl_arg_inc(dl);
4878                return cmd_port_unsplit(dl);
4879        } else if (dl_argv_match(dl, "param")) {
4880                dl_arg_inc(dl);
4881                return cmd_port_param(dl);
4882        } else if (dl_argv_match(dl, "function")) {
4883                dl_arg_inc(dl);
4884                return cmd_port_function(dl);
4885        } else if (dl_argv_match(dl, "health")) {
4886                dl_arg_inc(dl);
4887                if (dl_argv_match(dl, "list") || dl_no_arg(dl)
4888                    || (dl_argv_match(dl, "show") && dl_argc(dl) == 1)) {
4889                        dl_arg_inc(dl);
4890                        return __cmd_health_show(dl, false, true);
4891                } else {
4892                        return cmd_health(dl);
4893                }
4894        } else if (dl_argv_match(dl, "add")) {
4895                dl_arg_inc(dl);
4896                return cmd_port_add(dl);
4897        } else if (dl_argv_match(dl, "del")) {
4898                dl_arg_inc(dl);
4899                return cmd_port_del(dl);
4900        }
4901
4902        pr_err("Command \"%s\" not found\n", dl_argv(dl));
4903        return -ENOENT;
4904}
4905
4906static void cmd_sb_help(void)
4907{
4908        pr_err("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n");
4909        pr_err("       devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n");
4910        pr_err("       devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n");
4911        pr_err("                           size POOL_SIZE thtype { static | dynamic }\n");
4912        pr_err("       devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n");
4913        pr_err("                                   pool POOL_INDEX ]\n");
4914        pr_err("       devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n");
4915        pr_err("                                pool POOL_INDEX th THRESHOLD\n");
4916        pr_err("       devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
4917        pr_err("                                 type { ingress | egress } ]\n");
4918        pr_err("       devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
4919        pr_err("                              type { ingress | egress } pool POOL_INDEX\n");
4920        pr_err("                              th THRESHOLD\n");
4921        pr_err("       devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n");
4922        pr_err("       devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n");
4923        pr_err("       devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n");
4924}
4925
4926static void pr_out_sb(struct dl *dl, struct nlattr **tb)
4927{
4928        pr_out_handle_start_arr(dl, tb);
4929        check_indent_newline(dl);
4930        print_uint(PRINT_ANY, "sb", "sb %u",
4931                   mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
4932        print_uint(PRINT_ANY, "size", " size %u",
4933                   mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_SIZE]));
4934        print_uint(PRINT_ANY, "ing_pools", " ing_pools %u",
4935                   mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT]));
4936        print_uint(PRINT_ANY, "eg_pools", " eg_pools %u",
4937                   mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT]));
4938        print_uint(PRINT_ANY, "ing_tcs", " ing_tcs %u",
4939                   mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT]));
4940        print_uint(PRINT_ANY, "eg_tcs", " eg_tcs %u",
4941                   mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT]));
4942        pr_out_handle_end(dl);
4943}
4944
4945static int cmd_sb_show_cb(const struct nlmsghdr *nlh, void *data)
4946{
4947        struct dl *dl = data;
4948        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4949        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4950
4951        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4952        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4953            !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_SIZE] ||
4954            !tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT] ||
4955            !tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT] ||
4956            !tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT] ||
4957            !tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT])
4958                return MNL_CB_ERROR;
4959        pr_out_sb(dl, tb);
4960        return MNL_CB_OK;
4961}
4962
4963static int cmd_sb_show(struct dl *dl)
4964{
4965        struct nlmsghdr *nlh;
4966        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
4967        int err;
4968
4969        if (dl_argc(dl) == 0)
4970                flags |= NLM_F_DUMP;
4971
4972        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_GET, flags);
4973
4974        if (dl_argc(dl) > 0) {
4975                err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB);
4976                if (err)
4977                        return err;
4978        }
4979
4980        pr_out_section_start(dl, "sb");
4981        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_sb_show_cb, dl);
4982        pr_out_section_end(dl);
4983        return err;
4984}
4985
4986static const char *pool_type_name(uint8_t type)
4987{
4988        switch (type) {
4989        case DEVLINK_SB_POOL_TYPE_INGRESS: return "ingress";
4990        case DEVLINK_SB_POOL_TYPE_EGRESS: return "egress";
4991        default: return "<unknown type>";
4992        }
4993}
4994
4995static const char *threshold_type_name(uint8_t type)
4996{
4997        switch (type) {
4998        case DEVLINK_SB_THRESHOLD_TYPE_STATIC: return "static";
4999        case DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC: return "dynamic";
5000        default: return "<unknown type>";
5001        }
5002}
5003
5004static void pr_out_sb_pool(struct dl *dl, struct nlattr **tb)
5005{
5006        pr_out_handle_start_arr(dl, tb);
5007        check_indent_newline(dl);
5008        print_uint(PRINT_ANY, "sb", "sb %u",
5009                   mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
5010        print_uint(PRINT_ANY, "pool", " pool %u",
5011                   mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]));
5012        print_string(PRINT_ANY, "type", " type %s",
5013                     pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])));
5014        print_uint(PRINT_ANY, "size", " size %u",
5015                   mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_SIZE]));
5016        print_string(PRINT_ANY, "thtype", " thtype %s",
5017                     threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])));
5018        if (tb[DEVLINK_ATTR_SB_POOL_CELL_SIZE])
5019                print_uint(PRINT_ANY, "cell_size", " cell size %u",
5020                           mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_CELL_SIZE]));
5021        pr_out_handle_end(dl);
5022}
5023
5024static int cmd_sb_pool_show_cb(const struct nlmsghdr *nlh, void *data)
5025{
5026        struct dl *dl = data;
5027        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
5028        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
5029
5030        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5031        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5032            !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_INDEX] ||
5033            !tb[DEVLINK_ATTR_SB_POOL_TYPE] || !tb[DEVLINK_ATTR_SB_POOL_SIZE] ||
5034            !tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])
5035                return MNL_CB_ERROR;
5036        pr_out_sb_pool(dl, tb);
5037        return MNL_CB_OK;
5038}
5039
5040static int cmd_sb_pool_show(struct dl *dl)
5041{
5042        struct nlmsghdr *nlh;
5043        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
5044        int err;
5045
5046        if (dl_argc(dl) == 0)
5047                flags |= NLM_F_DUMP;
5048
5049        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_POOL_GET, flags);
5050
5051        if (dl_argc(dl) > 0) {
5052                err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL,
5053                                        DL_OPT_SB);
5054                if (err)
5055                        return err;
5056        }
5057
5058        pr_out_section_start(dl, "pool");
5059        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_sb_pool_show_cb, dl);
5060        pr_out_section_end(dl);
5061        return err;
5062}
5063
5064static int cmd_sb_pool_set(struct dl *dl)
5065{
5066        struct nlmsghdr *nlh;
5067        int err;
5068
5069        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_POOL_SET,
5070                               NLM_F_REQUEST | NLM_F_ACK);
5071
5072        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL |
5073                                DL_OPT_SB_SIZE | DL_OPT_SB_THTYPE, DL_OPT_SB);
5074        if (err)
5075                return err;
5076
5077        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
5078}
5079
5080static int cmd_sb_pool(struct dl *dl)
5081{
5082        if (dl_argv_match(dl, "help")) {
5083                cmd_sb_help();
5084                return 0;
5085        } else if (dl_argv_match(dl, "show") ||
5086                   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
5087                dl_arg_inc(dl);
5088                return cmd_sb_pool_show(dl);
5089        } else if (dl_argv_match(dl, "set")) {
5090                dl_arg_inc(dl);
5091                return cmd_sb_pool_set(dl);
5092        }
5093        pr_err("Command \"%s\" not found\n", dl_argv(dl));
5094        return -ENOENT;
5095}
5096
5097static void pr_out_sb_port_pool(struct dl *dl, struct nlattr **tb)
5098{
5099        pr_out_port_handle_start_arr(dl, tb, true);
5100        check_indent_newline(dl);
5101        print_uint(PRINT_ANY, "sb", "sb %u",
5102                   mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
5103        print_uint(PRINT_ANY, "pool", " pool %u",
5104                   mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]));
5105        print_uint(PRINT_ANY, "threshold", " threshold %u",
5106                   mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD]));
5107        pr_out_port_handle_end(dl);
5108}
5109
5110static int cmd_sb_port_pool_show_cb(const struct nlmsghdr *nlh, void *data)
5111{
5112        struct dl *dl = data;
5113        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
5114        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
5115
5116        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5117        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5118            !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
5119            !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD])
5120                return MNL_CB_ERROR;
5121        pr_out_sb_port_pool(dl, tb);
5122        return MNL_CB_OK;
5123}
5124
5125static int cmd_sb_port_pool_show(struct dl *dl)
5126{
5127        struct nlmsghdr *nlh;
5128        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
5129        int err;
5130
5131        if (dl_argc(dl) == 0)
5132                flags |= NLM_F_DUMP;
5133
5134        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags);
5135
5136        if (dl_argc(dl) > 0) {
5137                err = dl_argv_parse_put(nlh, dl,
5138                                        DL_OPT_HANDLEP | DL_OPT_SB_POOL,
5139                                        DL_OPT_SB);
5140                if (err)
5141                        return err;
5142        }
5143
5144        pr_out_section_start(dl, "port_pool");
5145        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_sb_port_pool_show_cb, dl);
5146        pr_out_section_end(dl);
5147        return 0;
5148}
5149
5150static int cmd_sb_port_pool_set(struct dl *dl)
5151{
5152        struct nlmsghdr *nlh;
5153        int err;
5154
5155        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_PORT_POOL_SET,
5156                               NLM_F_REQUEST | NLM_F_ACK);
5157
5158        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_POOL |
5159                                DL_OPT_SB_TH, DL_OPT_SB);
5160        if (err)
5161                return err;
5162
5163        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
5164}
5165
5166static int cmd_sb_port_pool(struct dl *dl)
5167{
5168        if (dl_argv_match(dl, "help")) {
5169                cmd_sb_help();
5170                return 0;
5171        } else if (dl_argv_match(dl, "show") ||
5172                   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
5173                dl_arg_inc(dl);
5174                return cmd_sb_port_pool_show(dl);
5175        } else if (dl_argv_match(dl, "set")) {
5176                dl_arg_inc(dl);
5177                return cmd_sb_port_pool_set(dl);
5178        }
5179        pr_err("Command \"%s\" not found\n", dl_argv(dl));
5180        return -ENOENT;
5181}
5182
5183static int cmd_sb_port(struct dl *dl)
5184{
5185        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
5186                cmd_sb_help();
5187                return 0;
5188        } else if (dl_argv_match(dl, "pool")) {
5189                dl_arg_inc(dl);
5190                return cmd_sb_port_pool(dl);
5191        }
5192        pr_err("Command \"%s\" not found\n", dl_argv(dl));
5193        return -ENOENT;
5194}
5195
5196static void pr_out_sb_tc_bind(struct dl *dl, struct nlattr **tb)
5197{
5198        pr_out_port_handle_start_arr(dl, tb, true);
5199        check_indent_newline(dl);
5200        print_uint(PRINT_ANY, "sb", "sb %u",
5201                   mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
5202        print_uint(PRINT_ANY, "tc", " tc %u",
5203                   mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]));
5204        print_string(PRINT_ANY, "type", " type %s",
5205                     pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])));
5206        print_uint(PRINT_ANY, "pool", " pool %u",
5207                   mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]));
5208        print_uint(PRINT_ANY, "threshold", " threshold %u",
5209                   mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD]));
5210        pr_out_port_handle_end(dl);
5211}
5212
5213static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr *nlh, void *data)
5214{
5215        struct dl *dl = data;
5216        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
5217        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
5218
5219        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5220        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5221            !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
5222            !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] ||
5223            !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD])
5224                return MNL_CB_ERROR;
5225        pr_out_sb_tc_bind(dl, tb);
5226        return MNL_CB_OK;
5227}
5228
5229static int cmd_sb_tc_bind_show(struct dl *dl)
5230{
5231        struct nlmsghdr *nlh;
5232        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
5233        int err;
5234
5235        if (dl_argc(dl) == 0)
5236                flags |= NLM_F_DUMP;
5237
5238        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags);
5239
5240        if (dl_argc(dl) > 0) {
5241                err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC |
5242                                        DL_OPT_SB_TYPE, DL_OPT_SB);
5243                if (err)
5244                        return err;
5245        }
5246
5247        pr_out_section_start(dl, "tc_bind");
5248        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_sb_tc_bind_show_cb, dl);
5249        pr_out_section_end(dl);
5250        return err;
5251}
5252
5253static int cmd_sb_tc_bind_set(struct dl *dl)
5254{
5255        struct nlmsghdr *nlh;
5256        int err;
5257
5258        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_SET,
5259                               NLM_F_REQUEST | NLM_F_ACK);
5260
5261        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC |
5262                                DL_OPT_SB_TYPE | DL_OPT_SB_POOL | DL_OPT_SB_TH,
5263                                DL_OPT_SB);
5264        if (err)
5265                return err;
5266
5267        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
5268}
5269
5270static int cmd_sb_tc_bind(struct dl *dl)
5271{
5272        if (dl_argv_match(dl, "help")) {
5273                cmd_sb_help();
5274                return 0;
5275        } else if (dl_argv_match(dl, "show") ||
5276                   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
5277                dl_arg_inc(dl);
5278                return cmd_sb_tc_bind_show(dl);
5279        } else if (dl_argv_match(dl, "set")) {
5280                dl_arg_inc(dl);
5281                return cmd_sb_tc_bind_set(dl);
5282        }
5283        pr_err("Command \"%s\" not found\n", dl_argv(dl));
5284        return -ENOENT;
5285}
5286
5287static int cmd_sb_tc(struct dl *dl)
5288{
5289        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
5290                cmd_sb_help();
5291                return 0;
5292        } else if (dl_argv_match(dl, "bind")) {
5293                dl_arg_inc(dl);
5294                return cmd_sb_tc_bind(dl);
5295        }
5296        pr_err("Command \"%s\" not found\n", dl_argv(dl));
5297        return -ENOENT;
5298}
5299
5300struct occ_item {
5301        struct list_head list;
5302        uint32_t index;
5303        uint32_t cur;
5304        uint32_t max;
5305        uint32_t bound_pool_index;
5306};
5307
5308struct occ_port {
5309        struct list_head list;
5310        char *bus_name;
5311        char *dev_name;
5312        uint32_t port_index;
5313        uint32_t sb_index;
5314        struct list_head pool_list;
5315        struct list_head ing_tc_list;
5316        struct list_head eg_tc_list;
5317};
5318
5319struct occ_show {
5320        struct dl *dl;
5321        int err;
5322        struct list_head port_list;
5323};
5324
5325static struct occ_item *occ_item_alloc(void)
5326{
5327        return calloc(1, sizeof(struct occ_item));
5328}
5329
5330static void occ_item_free(struct occ_item *occ_item)
5331{
5332        free(occ_item);
5333}
5334
5335static struct occ_port *occ_port_alloc(uint32_t port_index)
5336{
5337        struct occ_port *occ_port;
5338
5339        occ_port = calloc(1, sizeof(*occ_port));
5340        if (!occ_port)
5341                return NULL;
5342        occ_port->port_index = port_index;
5343        INIT_LIST_HEAD(&occ_port->pool_list);
5344        INIT_LIST_HEAD(&occ_port->ing_tc_list);
5345        INIT_LIST_HEAD(&occ_port->eg_tc_list);
5346        return occ_port;
5347}
5348
5349static void occ_port_free(struct occ_port *occ_port)
5350{
5351        struct occ_item *occ_item, *tmp;
5352
5353        list_for_each_entry_safe(occ_item, tmp, &occ_port->pool_list, list)
5354                occ_item_free(occ_item);
5355        list_for_each_entry_safe(occ_item, tmp, &occ_port->ing_tc_list, list)
5356                occ_item_free(occ_item);
5357        list_for_each_entry_safe(occ_item, tmp, &occ_port->eg_tc_list, list)
5358                occ_item_free(occ_item);
5359}
5360
5361static struct occ_show *occ_show_alloc(struct dl *dl)
5362{
5363        struct occ_show *occ_show;
5364
5365        occ_show = calloc(1, sizeof(*occ_show));
5366        if (!occ_show)
5367                return NULL;
5368        occ_show->dl = dl;
5369        INIT_LIST_HEAD(&occ_show->port_list);
5370        return occ_show;
5371}
5372
5373static void occ_show_free(struct occ_show *occ_show)
5374{
5375        struct occ_port *occ_port, *tmp;
5376
5377        list_for_each_entry_safe(occ_port, tmp, &occ_show->port_list, list)
5378                occ_port_free(occ_port);
5379}
5380
5381static struct occ_port *occ_port_get(struct occ_show *occ_show,
5382                                     struct nlattr **tb)
5383{
5384        struct occ_port *occ_port;
5385        uint32_t port_index;
5386
5387        port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]);
5388
5389        list_for_each_entry_reverse(occ_port, &occ_show->port_list, list) {
5390                if (occ_port->port_index == port_index)
5391                        return occ_port;
5392        }
5393        occ_port = occ_port_alloc(port_index);
5394        if (!occ_port)
5395                return NULL;
5396        list_add_tail(&occ_port->list, &occ_show->port_list);
5397        return occ_port;
5398}
5399
5400static void pr_out_occ_show_item_list(const char *label, struct list_head *list,
5401                                      bool bound_pool)
5402{
5403        struct occ_item *occ_item;
5404        int i = 1;
5405
5406        pr_out_sp(7, "  %s:", label);
5407        list_for_each_entry(occ_item, list, list) {
5408                if ((i - 1) % 4 == 0 && i != 1)
5409                        pr_out_sp(7, " ");
5410                if (bound_pool)
5411                        pr_out_sp(7, "%2u(%u):", occ_item->index,
5412                                  occ_item->bound_pool_index);
5413                else
5414                        pr_out_sp(7, "%2u:", occ_item->index);
5415                pr_out_sp(21, "%10u/%u", occ_item->cur, occ_item->max);
5416                if (i++ % 4 == 0)
5417                        pr_out("\n");
5418        }
5419        if ((i - 1) % 4 != 0)
5420                pr_out("\n");
5421}
5422
5423static void pr_out_json_occ_show_item_list(struct dl *dl, const char *label,
5424                                           struct list_head *list,
5425                                           bool bound_pool)
5426{
5427        struct occ_item *occ_item;
5428        char buf[32];
5429
5430        open_json_object(label);
5431        list_for_each_entry(occ_item, list, list) {
5432                sprintf(buf, "%u", occ_item->index);
5433                open_json_object(buf);
5434                if (bound_pool)
5435                        print_uint(PRINT_JSON, "bound_pool", NULL,
5436                                   occ_item->bound_pool_index);
5437                print_uint(PRINT_JSON, "current", NULL, occ_item->cur);
5438                print_uint(PRINT_JSON, "max", NULL, occ_item->max);
5439                close_json_object();
5440        }
5441        close_json_object();
5442}
5443
5444static void pr_out_occ_show_port(struct dl *dl, struct occ_port *occ_port)
5445{
5446        if (dl->json_output) {
5447                pr_out_json_occ_show_item_list(dl, "pool",
5448                                               &occ_port->pool_list, false);
5449                pr_out_json_occ_show_item_list(dl, "itc",
5450                                               &occ_port->ing_tc_list, true);
5451                pr_out_json_occ_show_item_list(dl, "etc",
5452                                               &occ_port->eg_tc_list, true);
5453        } else {
5454                pr_out("\n");
5455                pr_out_occ_show_item_list("pool", &occ_port->pool_list, false);
5456                pr_out_occ_show_item_list("itc", &occ_port->ing_tc_list, true);
5457                pr_out_occ_show_item_list("etc", &occ_port->eg_tc_list, true);
5458        }
5459}
5460
5461static void pr_out_occ_show(struct occ_show *occ_show)
5462{
5463        struct dl *dl = occ_show->dl;
5464        struct dl_opts *opts = &dl->opts;
5465        struct occ_port *occ_port;
5466
5467        list_for_each_entry(occ_port, &occ_show->port_list, list) {
5468                __pr_out_port_handle_start(dl, opts->bus_name, opts->dev_name,
5469                                           occ_port->port_index, true, false);
5470                pr_out_occ_show_port(dl, occ_port);
5471                pr_out_port_handle_end(dl);
5472        }
5473}
5474
5475static void cmd_sb_occ_port_pool_process(struct occ_show *occ_show,
5476                                         struct nlattr **tb)
5477{
5478        struct occ_port *occ_port;
5479        struct occ_item *occ_item;
5480
5481        if (occ_show->err || !dl_dump_filter(occ_show->dl, tb))
5482                return;
5483
5484        occ_port = occ_port_get(occ_show, tb);
5485        if (!occ_port) {
5486                occ_show->err = -ENOMEM;
5487                return;
5488        }
5489
5490        occ_item = occ_item_alloc();
5491        if (!occ_item) {
5492                occ_show->err = -ENOMEM;
5493                return;
5494        }
5495        occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]);
5496        occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]);
5497        occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]);
5498        list_add_tail(&occ_item->list, &occ_port->pool_list);
5499}
5500
5501static int cmd_sb_occ_port_pool_process_cb(const struct nlmsghdr *nlh, void *data)
5502{
5503        struct occ_show *occ_show = data;
5504        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
5505        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
5506
5507        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5508        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5509            !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
5510            !tb[DEVLINK_ATTR_SB_POOL_INDEX] ||
5511            !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX])
5512                return MNL_CB_ERROR;
5513        cmd_sb_occ_port_pool_process(occ_show, tb);
5514        return MNL_CB_OK;
5515}
5516
5517static void cmd_sb_occ_tc_pool_process(struct occ_show *occ_show,
5518                                       struct nlattr **tb)
5519{
5520        struct occ_port *occ_port;
5521        struct occ_item *occ_item;
5522        uint8_t pool_type;
5523
5524        if (occ_show->err || !dl_dump_filter(occ_show->dl, tb))
5525                return;
5526
5527        occ_port = occ_port_get(occ_show, tb);
5528        if (!occ_port) {
5529                occ_show->err = -ENOMEM;
5530                return;
5531        }
5532
5533        occ_item = occ_item_alloc();
5534        if (!occ_item) {
5535                occ_show->err = -ENOMEM;
5536                return;
5537        }
5538        occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]);
5539        occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]);
5540        occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]);
5541        occ_item->bound_pool_index =
5542                        mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]);
5543        pool_type = mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE]);
5544        if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS)
5545                list_add_tail(&occ_item->list, &occ_port->ing_tc_list);
5546        else if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS)
5547                list_add_tail(&occ_item->list, &occ_port->eg_tc_list);
5548        else
5549                occ_item_free(occ_item);
5550}
5551
5552static int cmd_sb_occ_tc_pool_process_cb(const struct nlmsghdr *nlh, void *data)
5553{
5554        struct occ_show *occ_show = data;
5555        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
5556        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
5557
5558        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5559        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5560            !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
5561            !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] ||
5562            !tb[DEVLINK_ATTR_SB_POOL_INDEX] ||
5563            !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX])
5564                return MNL_CB_ERROR;
5565        cmd_sb_occ_tc_pool_process(occ_show, tb);
5566        return MNL_CB_OK;
5567}
5568
5569static int cmd_sb_occ_show(struct dl *dl)
5570{
5571        struct nlmsghdr *nlh;
5572        struct occ_show *occ_show;
5573        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP;
5574        int err;
5575
5576        err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_HANDLEP, DL_OPT_SB);
5577        if (err)
5578                return err;
5579
5580        occ_show = occ_show_alloc(dl);
5581        if (!occ_show)
5582                return -ENOMEM;
5583
5584        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags);
5585
5586        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh,
5587                                  cmd_sb_occ_port_pool_process_cb, occ_show);
5588        if (err)
5589                goto out;
5590
5591        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags);
5592
5593        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh,
5594                                  cmd_sb_occ_tc_pool_process_cb, occ_show);
5595        if (err)
5596                goto out;
5597
5598        pr_out_section_start(dl, "occupancy");
5599        pr_out_occ_show(occ_show);
5600        pr_out_section_end(dl);
5601
5602out:
5603        occ_show_free(occ_show);
5604        return err;
5605}
5606
5607static int cmd_sb_occ_snapshot(struct dl *dl)
5608{
5609        struct nlmsghdr *nlh;
5610        int err;
5611
5612        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_OCC_SNAPSHOT,
5613                               NLM_F_REQUEST | NLM_F_ACK);
5614
5615        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB);
5616        if (err)
5617                return err;
5618
5619        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
5620}
5621
5622static int cmd_sb_occ_clearmax(struct dl *dl)
5623{
5624        struct nlmsghdr *nlh;
5625        int err;
5626
5627        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_OCC_MAX_CLEAR,
5628                               NLM_F_REQUEST | NLM_F_ACK);
5629
5630        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB);
5631        if (err)
5632                return err;
5633
5634        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
5635}
5636
5637static int cmd_sb_occ(struct dl *dl)
5638{
5639        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
5640                cmd_sb_help();
5641                return 0;
5642        } else if (dl_argv_match(dl, "show") ||
5643                   dl_argv_match(dl, "list")) {
5644                dl_arg_inc(dl);
5645                return cmd_sb_occ_show(dl);
5646        } else if (dl_argv_match(dl, "snapshot")) {
5647                dl_arg_inc(dl);
5648                return cmd_sb_occ_snapshot(dl);
5649        } else if (dl_argv_match(dl, "clearmax")) {
5650                dl_arg_inc(dl);
5651                return cmd_sb_occ_clearmax(dl);
5652        }
5653        pr_err("Command \"%s\" not found\n", dl_argv(dl));
5654        return -ENOENT;
5655}
5656
5657static int cmd_sb(struct dl *dl)
5658{
5659        if (dl_argv_match(dl, "help")) {
5660                cmd_sb_help();
5661                return 0;
5662        } else if (dl_argv_match(dl, "show") ||
5663                   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
5664                dl_arg_inc(dl);
5665                return cmd_sb_show(dl);
5666        } else if (dl_argv_match(dl, "pool")) {
5667                dl_arg_inc(dl);
5668                return cmd_sb_pool(dl);
5669        } else if (dl_argv_match(dl, "port")) {
5670                dl_arg_inc(dl);
5671                return cmd_sb_port(dl);
5672        } else if (dl_argv_match(dl, "tc")) {
5673                dl_arg_inc(dl);
5674                return cmd_sb_tc(dl);
5675        } else if (dl_argv_match(dl, "occupancy")) {
5676                dl_arg_inc(dl);
5677                return cmd_sb_occ(dl);
5678        }
5679        pr_err("Command \"%s\" not found\n", dl_argv(dl));
5680        return -ENOENT;
5681}
5682
5683static const char *cmd_name(uint8_t cmd)
5684{
5685        switch (cmd) {
5686        case DEVLINK_CMD_UNSPEC: return "unspec";
5687        case DEVLINK_CMD_GET: return "get";
5688        case DEVLINK_CMD_SET: return "set";
5689        case DEVLINK_CMD_NEW: return "new";
5690        case DEVLINK_CMD_DEL: return "del";
5691        case DEVLINK_CMD_PORT_GET: return "get";
5692        case DEVLINK_CMD_PORT_SET: return "set";
5693        case DEVLINK_CMD_PORT_NEW: return "new";
5694        case DEVLINK_CMD_PORT_DEL: return "del";
5695        case DEVLINK_CMD_PARAM_GET: return "get";
5696        case DEVLINK_CMD_PARAM_SET: return "set";
5697        case DEVLINK_CMD_PARAM_NEW: return "new";
5698        case DEVLINK_CMD_PARAM_DEL: return "del";
5699        case DEVLINK_CMD_REGION_GET: return "get";
5700        case DEVLINK_CMD_REGION_SET: return "set";
5701        case DEVLINK_CMD_REGION_NEW: return "new";
5702        case DEVLINK_CMD_REGION_DEL: return "del";
5703        case DEVLINK_CMD_PORT_PARAM_GET: return "get";
5704        case DEVLINK_CMD_PORT_PARAM_SET: return "set";
5705        case DEVLINK_CMD_PORT_PARAM_NEW: return "new";
5706        case DEVLINK_CMD_PORT_PARAM_DEL: return "del";
5707        case DEVLINK_CMD_FLASH_UPDATE: return "begin";
5708        case DEVLINK_CMD_FLASH_UPDATE_END: return "end";
5709        case DEVLINK_CMD_FLASH_UPDATE_STATUS: return "status";
5710        case DEVLINK_CMD_HEALTH_REPORTER_RECOVER: return "status";
5711        case DEVLINK_CMD_TRAP_GET: return "get";
5712        case DEVLINK_CMD_TRAP_SET: return "set";
5713        case DEVLINK_CMD_TRAP_NEW: return "new";
5714        case DEVLINK_CMD_TRAP_DEL: return "del";
5715        case DEVLINK_CMD_TRAP_GROUP_GET: return "get";
5716        case DEVLINK_CMD_TRAP_GROUP_SET: return "set";
5717        case DEVLINK_CMD_TRAP_GROUP_NEW: return "new";
5718        case DEVLINK_CMD_TRAP_GROUP_DEL: return "del";
5719        case DEVLINK_CMD_TRAP_POLICER_GET: return "get";
5720        case DEVLINK_CMD_TRAP_POLICER_SET: return "set";
5721        case DEVLINK_CMD_TRAP_POLICER_NEW: return "new";
5722        case DEVLINK_CMD_TRAP_POLICER_DEL: return "del";
5723        default: return "<unknown cmd>";
5724        }
5725}
5726
5727static const char *cmd_obj(uint8_t cmd)
5728{
5729        switch (cmd) {
5730        case DEVLINK_CMD_UNSPEC: return "unspec";
5731        case DEVLINK_CMD_GET:
5732        case DEVLINK_CMD_SET:
5733        case DEVLINK_CMD_NEW:
5734        case DEVLINK_CMD_DEL:
5735                return "dev";
5736        case DEVLINK_CMD_PORT_GET:
5737        case DEVLINK_CMD_PORT_SET:
5738        case DEVLINK_CMD_PORT_NEW:
5739        case DEVLINK_CMD_PORT_DEL:
5740                return "port";
5741        case DEVLINK_CMD_PARAM_GET:
5742        case DEVLINK_CMD_PARAM_SET:
5743        case DEVLINK_CMD_PARAM_NEW:
5744        case DEVLINK_CMD_PARAM_DEL:
5745        case DEVLINK_CMD_PORT_PARAM_GET:
5746        case DEVLINK_CMD_PORT_PARAM_SET:
5747        case DEVLINK_CMD_PORT_PARAM_NEW:
5748        case DEVLINK_CMD_PORT_PARAM_DEL:
5749                return "param";
5750        case DEVLINK_CMD_REGION_GET:
5751        case DEVLINK_CMD_REGION_SET:
5752        case DEVLINK_CMD_REGION_NEW:
5753        case DEVLINK_CMD_REGION_DEL:
5754                return "region";
5755        case DEVLINK_CMD_FLASH_UPDATE:
5756        case DEVLINK_CMD_FLASH_UPDATE_END:
5757        case DEVLINK_CMD_FLASH_UPDATE_STATUS:
5758                return "flash";
5759        case DEVLINK_CMD_HEALTH_REPORTER_RECOVER:
5760                return "health";
5761        case DEVLINK_CMD_TRAP_GET:
5762        case DEVLINK_CMD_TRAP_SET:
5763        case DEVLINK_CMD_TRAP_NEW:
5764        case DEVLINK_CMD_TRAP_DEL:
5765                return "trap";
5766        case DEVLINK_CMD_TRAP_GROUP_GET:
5767        case DEVLINK_CMD_TRAP_GROUP_SET:
5768        case DEVLINK_CMD_TRAP_GROUP_NEW:
5769        case DEVLINK_CMD_TRAP_GROUP_DEL:
5770                return "trap-group";
5771        case DEVLINK_CMD_TRAP_POLICER_GET:
5772        case DEVLINK_CMD_TRAP_POLICER_SET:
5773        case DEVLINK_CMD_TRAP_POLICER_NEW:
5774        case DEVLINK_CMD_TRAP_POLICER_DEL:
5775                return "trap-policer";
5776        default: return "<unknown obj>";
5777        }
5778}
5779
5780static void pr_out_mon_header(uint8_t cmd)
5781{
5782        if (!is_json_context()) {
5783                pr_out("[%s,%s] ", cmd_obj(cmd), cmd_name(cmd));
5784        } else {
5785                open_json_object(NULL);
5786                print_string(PRINT_JSON, "command", NULL, cmd_name(cmd));
5787                open_json_object(cmd_obj(cmd));
5788        }
5789}
5790
5791static void pr_out_mon_footer(void)
5792{
5793        if (is_json_context()) {
5794                close_json_object();
5795                close_json_object();
5796        }
5797}
5798
5799static bool cmd_filter_check(struct dl *dl, uint8_t cmd)
5800{
5801        const char *obj = cmd_obj(cmd);
5802        unsigned int index = 0;
5803        const char *cur_obj;
5804
5805        if (dl_no_arg(dl))
5806                return true;
5807        while ((cur_obj = dl_argv_index(dl, index++))) {
5808                if (strcmp(cur_obj, obj) == 0 || strcmp(cur_obj, "all") == 0)
5809                        return true;
5810        }
5811        return false;
5812}
5813
5814static void pr_out_flash_update(struct dl *dl, struct nlattr **tb)
5815{
5816        __pr_out_handle_start(dl, tb, true, false);
5817
5818        if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG]) {
5819                check_indent_newline(dl);
5820                print_string(PRINT_ANY, "msg", "msg %s",
5821                             mnl_attr_get_str(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG]));
5822        }
5823        if (tb[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT]) {
5824                check_indent_newline(dl);
5825                print_string(PRINT_ANY, "component", "component %s",
5826                             mnl_attr_get_str(tb[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT]));
5827        }
5828
5829        if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE])
5830                pr_out_u64(dl, "done",
5831                           mnl_attr_get_u64(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE]));
5832
5833        if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL])
5834                pr_out_u64(dl, "total",
5835                           mnl_attr_get_u64(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL]));
5836
5837        pr_out_handle_end(dl);
5838}
5839
5840static void pr_out_region(struct dl *dl, struct nlattr **tb);
5841static void pr_out_health(struct dl *dl, struct nlattr **tb_health,
5842                          bool show_device, bool show_port);
5843static void pr_out_trap(struct dl *dl, struct nlattr **tb, bool array);
5844static void pr_out_trap_group(struct dl *dl, struct nlattr **tb, bool array);
5845static void pr_out_trap_policer(struct dl *dl, struct nlattr **tb, bool array);
5846
5847static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data)
5848{
5849        struct dl *dl = data;
5850        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
5851        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
5852        uint8_t cmd = genl->cmd;
5853
5854        if (!cmd_filter_check(dl, cmd))
5855                return MNL_CB_OK;
5856
5857        switch (cmd) {
5858        case DEVLINK_CMD_GET: /* fall through */
5859        case DEVLINK_CMD_SET: /* fall through */
5860        case DEVLINK_CMD_NEW: /* fall through */
5861        case DEVLINK_CMD_DEL:
5862                mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5863                if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
5864                        return MNL_CB_ERROR;
5865                pr_out_mon_header(genl->cmd);
5866                dl->stats = true;
5867                pr_out_dev(dl, tb);
5868                pr_out_mon_footer();
5869                break;
5870        case DEVLINK_CMD_PORT_GET: /* fall through */
5871        case DEVLINK_CMD_PORT_SET: /* fall through */
5872        case DEVLINK_CMD_PORT_NEW: /* fall through */
5873        case DEVLINK_CMD_PORT_DEL:
5874                mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5875                if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5876                    !tb[DEVLINK_ATTR_PORT_INDEX])
5877                        return MNL_CB_ERROR;
5878                pr_out_mon_header(genl->cmd);
5879                pr_out_port(dl, tb);
5880                pr_out_mon_footer();
5881                break;
5882        case DEVLINK_CMD_PARAM_GET: /* fall through */
5883        case DEVLINK_CMD_PARAM_SET: /* fall through */
5884        case DEVLINK_CMD_PARAM_NEW: /* fall through */
5885        case DEVLINK_CMD_PARAM_DEL:
5886                mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5887                if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5888                    !tb[DEVLINK_ATTR_PARAM])
5889                        return MNL_CB_ERROR;
5890                pr_out_mon_header(genl->cmd);
5891                pr_out_param(dl, tb, false, false);
5892                pr_out_mon_footer();
5893                break;
5894        case DEVLINK_CMD_REGION_GET: /* fall through */
5895        case DEVLINK_CMD_REGION_SET: /* fall through */
5896        case DEVLINK_CMD_REGION_NEW: /* fall through */
5897        case DEVLINK_CMD_REGION_DEL:
5898                mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5899                if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5900                    !tb[DEVLINK_ATTR_REGION_NAME])
5901                        return MNL_CB_ERROR;
5902                pr_out_mon_header(genl->cmd);
5903                pr_out_region(dl, tb);
5904                pr_out_mon_footer();
5905                break;
5906        case DEVLINK_CMD_FLASH_UPDATE: /* fall through */
5907        case DEVLINK_CMD_FLASH_UPDATE_END: /* fall through */
5908        case DEVLINK_CMD_FLASH_UPDATE_STATUS:
5909                mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5910                if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
5911                        return MNL_CB_ERROR;
5912                pr_out_mon_header(genl->cmd);
5913                pr_out_flash_update(dl, tb);
5914                pr_out_mon_footer();
5915                break;
5916        case DEVLINK_CMD_HEALTH_REPORTER_RECOVER:
5917                mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5918                if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5919                    !tb[DEVLINK_ATTR_HEALTH_REPORTER])
5920                        return MNL_CB_ERROR;
5921                pr_out_mon_header(genl->cmd);
5922                pr_out_health(dl, tb, true, true);
5923                pr_out_mon_footer();
5924                break;
5925        case DEVLINK_CMD_TRAP_GET: /* fall through */
5926        case DEVLINK_CMD_TRAP_SET: /* fall through */
5927        case DEVLINK_CMD_TRAP_NEW: /* fall through */
5928        case DEVLINK_CMD_TRAP_DEL:
5929                mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5930                if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5931                    !tb[DEVLINK_ATTR_TRAP_NAME] ||
5932                    !tb[DEVLINK_ATTR_TRAP_TYPE] ||
5933                    !tb[DEVLINK_ATTR_TRAP_ACTION] ||
5934                    !tb[DEVLINK_ATTR_TRAP_GROUP_NAME] ||
5935                    !tb[DEVLINK_ATTR_TRAP_METADATA] ||
5936                    !tb[DEVLINK_ATTR_STATS])
5937                        return MNL_CB_ERROR;
5938                pr_out_mon_header(genl->cmd);
5939                pr_out_trap(dl, tb, false);
5940                pr_out_mon_footer();
5941                break;
5942        case DEVLINK_CMD_TRAP_GROUP_GET: /* fall through */
5943        case DEVLINK_CMD_TRAP_GROUP_SET: /* fall through */
5944        case DEVLINK_CMD_TRAP_GROUP_NEW: /* fall through */
5945        case DEVLINK_CMD_TRAP_GROUP_DEL:
5946                mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5947                if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5948                    !tb[DEVLINK_ATTR_TRAP_GROUP_NAME] ||
5949                    !tb[DEVLINK_ATTR_STATS])
5950                        return MNL_CB_ERROR;
5951                pr_out_mon_header(genl->cmd);
5952                pr_out_trap_group(dl, tb, false);
5953                pr_out_mon_footer();
5954                break;
5955        case DEVLINK_CMD_TRAP_POLICER_GET: /* fall through */
5956        case DEVLINK_CMD_TRAP_POLICER_SET: /* fall through */
5957        case DEVLINK_CMD_TRAP_POLICER_NEW: /* fall through */
5958        case DEVLINK_CMD_TRAP_POLICER_DEL: /* fall through */
5959                mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5960                if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5961                    !tb[DEVLINK_ATTR_TRAP_POLICER_ID] ||
5962                    !tb[DEVLINK_ATTR_TRAP_POLICER_RATE] ||
5963                    !tb[DEVLINK_ATTR_TRAP_POLICER_BURST])
5964                        return MNL_CB_ERROR;
5965                pr_out_mon_header(genl->cmd);
5966                pr_out_trap_policer(dl, tb, false);
5967                break;
5968        }
5969        fflush(stdout);
5970        return MNL_CB_OK;
5971}
5972
5973static int cmd_mon_show(struct dl *dl)
5974{
5975        int err;
5976        unsigned int index = 0;
5977        const char *cur_obj;
5978
5979        while ((cur_obj = dl_argv_index(dl, index++))) {
5980                if (strcmp(cur_obj, "all") != 0 &&
5981                    strcmp(cur_obj, "dev") != 0 &&
5982                    strcmp(cur_obj, "port") != 0 &&
5983                    strcmp(cur_obj, "health") != 0 &&
5984                    strcmp(cur_obj, "trap") != 0 &&
5985                    strcmp(cur_obj, "trap-group") != 0 &&
5986                    strcmp(cur_obj, "trap-policer") != 0) {
5987                        pr_err("Unknown object \"%s\"\n", cur_obj);
5988                        return -EINVAL;
5989                }
5990        }
5991        err = _mnlg_socket_group_add(&dl->nlg, DEVLINK_GENL_MCGRP_CONFIG_NAME);
5992        if (err)
5993                return err;
5994        open_json_object(NULL);
5995        open_json_array(PRINT_JSON, "mon");
5996        err = _mnlg_socket_recv_run_intr(&dl->nlg, cmd_mon_show_cb, dl);
5997        close_json_array(PRINT_JSON, NULL);
5998        close_json_object();
5999        if (err)
6000                return err;
6001        return 0;
6002}
6003
6004static void cmd_mon_help(void)
6005{
6006        pr_err("Usage: devlink monitor [ all | OBJECT-LIST ]\n"
6007               "where  OBJECT-LIST := { dev | port | health | trap | trap-group | trap-policer }\n");
6008}
6009
6010static int cmd_mon(struct dl *dl)
6011{
6012        if (dl_argv_match(dl, "help")) {
6013                cmd_mon_help();
6014                return 0;
6015        }
6016        return cmd_mon_show(dl);
6017}
6018
6019struct dpipe_field {
6020        char *name;
6021        unsigned int id;
6022        unsigned int bitwidth;
6023        enum devlink_dpipe_field_mapping_type mapping_type;
6024};
6025
6026struct dpipe_header {
6027        struct list_head list;
6028        char *name;
6029        unsigned int id;
6030        struct dpipe_field *fields;
6031        unsigned int fields_count;
6032};
6033
6034struct dpipe_table {
6035        struct list_head list;
6036        char *name;
6037        unsigned int resource_id;
6038        bool resource_valid;
6039};
6040
6041struct dpipe_tables {
6042        struct list_head table_list;
6043};
6044
6045struct resource {
6046        char *name;
6047        uint64_t size;
6048        uint64_t size_new;
6049        uint64_t size_min;
6050        uint64_t size_max;
6051        uint64_t size_gran;
6052        enum devlink_resource_unit unit;
6053        bool size_valid;
6054        uint64_t size_occ;
6055        bool occ_valid;
6056        uint64_t id;
6057        struct list_head list;
6058        struct list_head resource_list;
6059        struct resource *parent;
6060};
6061
6062struct resources {
6063        struct list_head resource_list;
6064};
6065
6066struct resource_ctx {
6067        struct dl *dl;
6068        int err;
6069        struct resources *resources;
6070        struct dpipe_tables *tables;
6071        bool print_resources;
6072        bool pending_change;
6073};
6074
6075static struct resource *resource_alloc(void)
6076{
6077        struct resource *resource;
6078
6079        resource = calloc(1, sizeof(struct resource));
6080        if (!resource)
6081                return NULL;
6082        INIT_LIST_HEAD(&resource->resource_list);
6083        return resource;
6084}
6085
6086static void resource_free(struct resource *resource)
6087{
6088        struct resource *child_resource, *tmp;
6089
6090        list_for_each_entry_safe(child_resource, tmp, &resource->resource_list,
6091                                 list) {
6092                free(child_resource->name);
6093                resource_free(child_resource);
6094        }
6095        free(resource);
6096}
6097
6098static struct resources *resources_alloc(void)
6099{
6100        struct resources *resources;
6101
6102        resources = calloc(1, sizeof(struct resources));
6103        if (!resources)
6104                return NULL;
6105        INIT_LIST_HEAD(&resources->resource_list);
6106        return resources;
6107}
6108
6109static void resources_free(struct resources *resources)
6110{
6111        struct resource *resource, *tmp;
6112
6113        list_for_each_entry_safe(resource, tmp, &resources->resource_list, list)
6114                resource_free(resource);
6115}
6116
6117static int resource_ctx_init(struct resource_ctx *ctx, struct dl *dl)
6118{
6119        ctx->resources = resources_alloc();
6120        if (!ctx->resources)
6121                return -ENOMEM;
6122        ctx->dl = dl;
6123        return 0;
6124}
6125
6126static void resource_ctx_fini(struct resource_ctx *ctx)
6127{
6128        resources_free(ctx->resources);
6129}
6130
6131struct dpipe_ctx {
6132        struct dl *dl;
6133        int err;
6134        struct list_head global_headers;
6135        struct list_head local_headers;
6136        struct dpipe_tables *tables;
6137        struct resources *resources;
6138        bool print_headers;
6139        bool print_tables;
6140};
6141
6142static struct dpipe_header *dpipe_header_alloc(unsigned int fields_count)
6143{
6144        struct dpipe_header *header;
6145
6146        header = calloc(1, sizeof(struct dpipe_header));
6147        if (!header)
6148                return NULL;
6149        header->fields = calloc(fields_count, sizeof(struct dpipe_field));
6150        if (!header->fields)
6151                goto err_fields_alloc;
6152        header->fields_count = fields_count;
6153        return header;
6154
6155err_fields_alloc:
6156        free(header);
6157        return NULL;
6158}
6159
6160static void dpipe_header_free(struct dpipe_header *header)
6161{
6162        free(header->fields);
6163        free(header);
6164}
6165
6166static void dpipe_header_clear(struct dpipe_header *header)
6167{
6168        struct dpipe_field *field;
6169        int i;
6170
6171        for (i = 0; i < header->fields_count; i++) {
6172                field = &header->fields[i];
6173                free(field->name);
6174        }
6175        free(header->name);
6176}
6177
6178static void dpipe_header_add(struct dpipe_ctx *ctx,
6179                             struct dpipe_header *header, bool global)
6180{
6181        if (global)
6182                list_add(&header->list, &ctx->global_headers);
6183        else
6184                list_add(&header->list, &ctx->local_headers);
6185}
6186
6187static void dpipe_header_del(struct dpipe_header *header)
6188{
6189        list_del(&header->list);
6190}
6191
6192static struct dpipe_table *dpipe_table_alloc(void)
6193{
6194        return calloc(1, sizeof(struct dpipe_table));
6195}
6196
6197static void dpipe_table_free(struct dpipe_table *table)
6198{
6199        free(table);
6200}
6201
6202static struct dpipe_tables *dpipe_tables_alloc(void)
6203{
6204        struct dpipe_tables *tables;
6205
6206        tables = calloc(1, sizeof(struct dpipe_tables));
6207        if (!tables)
6208                return NULL;
6209        INIT_LIST_HEAD(&tables->table_list);
6210        return tables;
6211}
6212
6213static void dpipe_tables_free(struct dpipe_tables *tables)
6214{
6215        struct dpipe_table *table, *tmp;
6216
6217        list_for_each_entry_safe(table, tmp, &tables->table_list, list)
6218                dpipe_table_free(table);
6219        free(tables);
6220}
6221
6222static int dpipe_ctx_init(struct dpipe_ctx *ctx, struct dl *dl)
6223{
6224        ctx->tables = dpipe_tables_alloc();
6225        if (!ctx->tables)
6226                return -ENOMEM;
6227
6228        ctx->dl = dl;
6229        INIT_LIST_HEAD(&ctx->global_headers);
6230        INIT_LIST_HEAD(&ctx->local_headers);
6231        return 0;
6232}
6233
6234static void dpipe_ctx_fini(struct dpipe_ctx *ctx)
6235{
6236        struct dpipe_header *header, *tmp;
6237
6238        list_for_each_entry_safe(header, tmp, &ctx->global_headers,
6239                                 list) {
6240                dpipe_header_del(header);
6241                dpipe_header_clear(header);
6242                dpipe_header_free(header);
6243        }
6244        list_for_each_entry_safe(header, tmp, &ctx->local_headers,
6245                                 list) {
6246                dpipe_header_del(header);
6247                dpipe_header_clear(header);
6248                dpipe_header_free(header);
6249        }
6250        dpipe_tables_free(ctx->tables);
6251}
6252
6253static const char *dpipe_header_id2s(struct dpipe_ctx *ctx,
6254                                     uint32_t header_id, bool global)
6255{
6256        struct list_head *header_list;
6257        struct dpipe_header *header;
6258
6259        if (global)
6260                header_list = &ctx->global_headers;
6261        else
6262                header_list = &ctx->local_headers;
6263        list_for_each_entry(header, header_list, list) {
6264                if (header->id != header_id)
6265                        continue;
6266                return header->name;
6267        }
6268        return NULL;
6269}
6270
6271static const char *dpipe_field_id2s(struct dpipe_ctx *ctx,
6272                                    uint32_t header_id,
6273                                    uint32_t field_id, bool global)
6274{
6275        struct list_head *header_list;
6276        struct dpipe_header *header;
6277
6278        if (global)
6279                header_list = &ctx->global_headers;
6280        else
6281                header_list = &ctx->local_headers;
6282        list_for_each_entry(header, header_list, list) {
6283                if (header->id != header_id)
6284                        continue;
6285                return header->fields[field_id].name;
6286        }
6287        return NULL;
6288}
6289
6290static const char *
6291dpipe_field_mapping_e2s(enum devlink_dpipe_field_mapping_type mapping_type)
6292{
6293        switch (mapping_type) {
6294        case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_NONE:
6295                return NULL;
6296        case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX:
6297                return "ifindex";
6298        default:
6299                return "<unknown>";
6300        }
6301}
6302
6303static const char *
6304dpipe_mapping_get(struct dpipe_ctx *ctx, uint32_t header_id,
6305                  uint32_t field_id, bool global)
6306{
6307        enum devlink_dpipe_field_mapping_type mapping_type;
6308        struct list_head *header_list;
6309        struct dpipe_header *header;
6310
6311        if (global)
6312                header_list = &ctx->global_headers;
6313        else
6314                header_list = &ctx->local_headers;
6315        list_for_each_entry(header, header_list, list) {
6316                if (header->id != header_id)
6317                        continue;
6318                mapping_type = header->fields[field_id].mapping_type;
6319                return dpipe_field_mapping_e2s(mapping_type);
6320        }
6321        return NULL;
6322}
6323
6324static void pr_out_dpipe_fields(struct dpipe_ctx *ctx,
6325                                struct dpipe_field *fields,
6326                                unsigned int field_count)
6327{
6328        struct dpipe_field *field;
6329        int i;
6330
6331        for (i = 0; i < field_count; i++) {
6332                field = &fields[i];
6333                pr_out_entry_start(ctx->dl);
6334                check_indent_newline(ctx->dl);
6335                print_string(PRINT_ANY, "name", "name %s", field->name);
6336                if (ctx->dl->verbose)
6337                        print_uint(PRINT_ANY, "id", " id %u", field->id);
6338                print_uint(PRINT_ANY, "bitwidth", " bitwidth %u", field->bitwidth);
6339                if (field->mapping_type) {
6340                        print_string(PRINT_ANY, "mapping_type", " mapping_type %s",
6341                                     dpipe_field_mapping_e2s(field->mapping_type));
6342                }
6343                pr_out_entry_end(ctx->dl);
6344        }
6345}
6346
6347static void
6348pr_out_dpipe_header(struct dpipe_ctx *ctx, struct nlattr **tb,
6349                    struct dpipe_header *header, bool global)
6350{
6351        pr_out_handle_start_arr(ctx->dl, tb);
6352        check_indent_newline(ctx->dl);
6353        print_string(PRINT_ANY, "name", "name %s", header->name);
6354        if (ctx->dl->verbose) {
6355                print_uint(PRINT_ANY, "id", " id %u", header->id);
6356                print_bool(PRINT_ANY, "global", " global %s", global);
6357        }
6358        pr_out_array_start(ctx->dl, "field");
6359        pr_out_dpipe_fields(ctx, header->fields,
6360                            header->fields_count);
6361        pr_out_array_end(ctx->dl);
6362        pr_out_handle_end(ctx->dl);
6363}
6364
6365static void pr_out_dpipe_headers(struct dpipe_ctx *ctx,
6366                                 struct nlattr **tb)
6367{
6368        struct dpipe_header *header;
6369
6370        list_for_each_entry(header, &ctx->local_headers, list)
6371                pr_out_dpipe_header(ctx, tb, header, false);
6372
6373        list_for_each_entry(header, &ctx->global_headers, list)
6374                pr_out_dpipe_header(ctx, tb, header, true);
6375}
6376
6377static int dpipe_header_field_get(struct nlattr *nl, struct dpipe_field *field)
6378{
6379        struct nlattr *nla_field[DEVLINK_ATTR_MAX + 1] = {};
6380        const char *name;
6381        int err;
6382
6383        err = mnl_attr_parse_nested(nl, attr_cb, nla_field);
6384        if (err != MNL_CB_OK)
6385                return -EINVAL;
6386        if (!nla_field[DEVLINK_ATTR_DPIPE_FIELD_ID] ||
6387            !nla_field[DEVLINK_ATTR_DPIPE_FIELD_NAME] ||
6388            !nla_field[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH] ||
6389            !nla_field[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE])
6390                return -EINVAL;
6391
6392        name = mnl_attr_get_str(nla_field[DEVLINK_ATTR_DPIPE_FIELD_NAME]);
6393        field->id = mnl_attr_get_u32(nla_field[DEVLINK_ATTR_DPIPE_FIELD_ID]);
6394        field->bitwidth = mnl_attr_get_u32(nla_field[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH]);
6395        field->name = strdup(name);
6396        if (!field->name)
6397                return -ENOMEM;
6398        field->mapping_type = mnl_attr_get_u32(nla_field[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE]);
6399        return 0;
6400}
6401
6402static int dpipe_header_fields_get(struct nlattr *nla_fields,
6403                                   struct dpipe_field *fields)
6404{
6405        struct nlattr *nla_field;
6406        int count = 0;
6407        int err;
6408
6409        mnl_attr_for_each_nested(nla_field, nla_fields) {
6410                err = dpipe_header_field_get(nla_field, &fields[count]);
6411                if (err)
6412                        return err;
6413                count++;
6414        }
6415        return 0;
6416}
6417
6418static unsigned int dpipe_header_field_count_get(struct nlattr *nla_fields)
6419{
6420        struct nlattr *nla_field;
6421        unsigned int count = 0;
6422
6423        mnl_attr_for_each_nested(nla_field, nla_fields)
6424                count++;
6425        return count;
6426}
6427
6428static int dpipe_header_get(struct dpipe_ctx *ctx, struct nlattr *nl)
6429{
6430        struct nlattr *nla_header[DEVLINK_ATTR_MAX + 1] = {};
6431        struct dpipe_header *header;
6432        unsigned int fields_count;
6433        const char *header_name;
6434        bool global;
6435        int err;
6436
6437        err = mnl_attr_parse_nested(nl, attr_cb, nla_header);
6438        if (err != MNL_CB_OK)
6439                return -EINVAL;
6440
6441        if (!nla_header[DEVLINK_ATTR_DPIPE_HEADER_NAME] ||
6442            !nla_header[DEVLINK_ATTR_DPIPE_HEADER_ID] ||
6443            !nla_header[DEVLINK_ATTR_DPIPE_HEADER_FIELDS])
6444                return -EINVAL;
6445
6446        fields_count = dpipe_header_field_count_get(nla_header[DEVLINK_ATTR_DPIPE_HEADER_FIELDS]);
6447        header = dpipe_header_alloc(fields_count);
6448        if (!header)
6449                return -ENOMEM;
6450
6451        header_name = mnl_attr_get_str(nla_header[DEVLINK_ATTR_DPIPE_HEADER_NAME]);
6452        header->name = strdup(header_name);
6453        header->id = mnl_attr_get_u32(nla_header[DEVLINK_ATTR_DPIPE_HEADER_ID]);
6454        header->fields_count = fields_count;
6455        global = !!mnl_attr_get_u8(nla_header[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL]);
6456
6457        err = dpipe_header_fields_get(nla_header[DEVLINK_ATTR_DPIPE_HEADER_FIELDS],
6458                                      header->fields);
6459        if (err)
6460                goto err_field_get;
6461        dpipe_header_add(ctx, header, global);
6462        return 0;
6463
6464err_field_get:
6465        dpipe_header_free(header);
6466        return err;
6467}
6468
6469static int dpipe_headers_get(struct dpipe_ctx *ctx, struct nlattr **tb)
6470{
6471        struct nlattr *nla_headers = tb[DEVLINK_ATTR_DPIPE_HEADERS];
6472        struct nlattr *nla_header;
6473        int err;
6474
6475        mnl_attr_for_each_nested(nla_header, nla_headers) {
6476                err = dpipe_header_get(ctx, nla_header);
6477                if (err)
6478                        return err;
6479        }
6480        return 0;
6481}
6482
6483static int cmd_dpipe_header_cb(const struct nlmsghdr *nlh, void *data)
6484{
6485        struct dpipe_ctx *ctx = data;
6486        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
6487        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
6488        int err;
6489
6490        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
6491        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
6492            !tb[DEVLINK_ATTR_DPIPE_HEADERS])
6493                return MNL_CB_ERROR;
6494        err = dpipe_headers_get(ctx, tb);
6495        if (err) {
6496                ctx->err = err;
6497                return MNL_CB_ERROR;
6498        }
6499
6500        if (ctx->print_headers)
6501                pr_out_dpipe_headers(ctx, tb);
6502        return MNL_CB_OK;
6503}
6504
6505static int cmd_dpipe_headers_show(struct dl *dl)
6506{
6507        struct nlmsghdr *nlh;
6508        struct dpipe_ctx ctx = {};
6509        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
6510        int err;
6511
6512        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags);
6513
6514        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
6515        if (err)
6516                return err;
6517
6518        err = dpipe_ctx_init(&ctx, dl);
6519        if (err)
6520                return err;
6521
6522        ctx.print_headers = true;
6523
6524        pr_out_section_start(dl, "header");
6525        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_dpipe_header_cb, &ctx);
6526        if (err)
6527                pr_err("error get headers %s\n", strerror(ctx.err));
6528        pr_out_section_end(dl);
6529
6530        dpipe_ctx_fini(&ctx);
6531        return err;
6532}
6533
6534static void cmd_dpipe_help(void)
6535{
6536        pr_err("Usage: devlink dpipe table show DEV [ name TABLE_NAME ]\n");
6537        pr_err("       devlink dpipe table set DEV name TABLE_NAME\n");
6538        pr_err("                               [ counters_enabled { true | false } ]\n");
6539        pr_err("       devlink dpipe table dump DEV name TABLE_NAME\n");
6540        pr_err("       devlink dpipe header show DEV\n");
6541}
6542
6543static int cmd_dpipe_header(struct dl *dl)
6544{
6545        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
6546                cmd_dpipe_help();
6547                return 0;
6548        } else if (dl_argv_match(dl, "show")) {
6549                dl_arg_inc(dl);
6550                return cmd_dpipe_headers_show(dl);
6551        }
6552        pr_err("Command \"%s\" not found\n", dl_argv(dl));
6553        return -ENOENT;
6554}
6555
6556static const char
6557*dpipe_action_type_e2s(enum devlink_dpipe_action_type action_type)
6558{
6559        switch (action_type) {
6560        case DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY:
6561                return "field_modify";
6562        default:
6563                return "<unknown>";
6564        }
6565}
6566
6567struct dpipe_op_info {
6568        uint32_t header_id;
6569        uint32_t field_id;
6570        bool header_global;
6571};
6572
6573struct dpipe_action {
6574        struct dpipe_op_info info;
6575        uint32_t type;
6576};
6577
6578static void pr_out_dpipe_action(struct dpipe_action *action,
6579                                struct dpipe_ctx *ctx)
6580{
6581        struct dpipe_op_info *op_info = &action->info;
6582        const char *mapping;
6583
6584        check_indent_newline(ctx->dl);
6585        print_string(PRINT_ANY, "type", "type %s",
6586                     dpipe_action_type_e2s(action->type));
6587        print_string(PRINT_ANY, "header", " header %s",
6588                     dpipe_header_id2s(ctx, op_info->header_id,
6589                                       op_info->header_global));
6590        print_string(PRINT_ANY, "field", " field %s",
6591                     dpipe_field_id2s(ctx, op_info->header_id,
6592                                      op_info->field_id,
6593                                      op_info->header_global));
6594        mapping = dpipe_mapping_get(ctx, op_info->header_id,
6595                                    op_info->field_id,
6596                                    op_info->header_global);
6597        if (mapping)
6598                print_string(PRINT_ANY, "mapping", " mapping %s", mapping);
6599}
6600
6601static int dpipe_action_parse(struct dpipe_action *action, struct nlattr *nl)
6602{
6603        struct nlattr *nla_action[DEVLINK_ATTR_MAX + 1] = {};
6604        int err;
6605
6606        err = mnl_attr_parse_nested(nl, attr_cb, nla_action);
6607        if (err != MNL_CB_OK)
6608                return -EINVAL;
6609
6610        if (!nla_action[DEVLINK_ATTR_DPIPE_ACTION_TYPE] ||
6611            !nla_action[DEVLINK_ATTR_DPIPE_HEADER_INDEX] ||
6612            !nla_action[DEVLINK_ATTR_DPIPE_HEADER_ID] ||
6613            !nla_action[DEVLINK_ATTR_DPIPE_FIELD_ID]) {
6614                return -EINVAL;
6615        }
6616
6617        action->type = mnl_attr_get_u32(nla_action[DEVLINK_ATTR_DPIPE_ACTION_TYPE]);
6618        action->info.header_id = mnl_attr_get_u32(nla_action[DEVLINK_ATTR_DPIPE_HEADER_ID]);
6619        action->info.field_id = mnl_attr_get_u32(nla_action[DEVLINK_ATTR_DPIPE_FIELD_ID]);
6620        action->info.header_global = !!mnl_attr_get_u8(nla_action[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL]);
6621
6622        return 0;
6623}
6624
6625static int dpipe_table_actions_show(struct dpipe_ctx *ctx,
6626                                    struct nlattr *nla_actions)
6627{
6628        struct nlattr *nla_action;
6629        struct dpipe_action action;
6630
6631        mnl_attr_for_each_nested(nla_action, nla_actions) {
6632                pr_out_entry_start(ctx->dl);
6633                if (dpipe_action_parse(&action, nla_action))
6634                        goto err_action_parse;
6635                pr_out_dpipe_action(&action, ctx);
6636                pr_out_entry_end(ctx->dl);
6637        }
6638        return 0;
6639
6640err_action_parse:
6641        pr_out_entry_end(ctx->dl);
6642        return -EINVAL;
6643}
6644
6645static const char *
6646dpipe_match_type_e2s(enum devlink_dpipe_match_type match_type)
6647{
6648        switch (match_type) {
6649        case DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT:
6650                return "field_exact";
6651        default:
6652                return "<unknown>";
6653        }
6654}
6655
6656struct dpipe_match {
6657        struct dpipe_op_info info;
6658        uint32_t type;
6659};
6660
6661static void pr_out_dpipe_match(struct dpipe_match *match,
6662                               struct dpipe_ctx *ctx)
6663{
6664        struct dpipe_op_info *op_info = &match->info;
6665        const char *mapping;
6666
6667        check_indent_newline(ctx->dl);
6668        print_string(PRINT_ANY, "type", "type %s",
6669                     dpipe_match_type_e2s(match->type));
6670        print_string(PRINT_ANY, "header", " header %s",
6671                     dpipe_header_id2s(ctx, op_info->header_id,
6672                                       op_info->header_global));
6673        print_string(PRINT_ANY, "field", " field %s",
6674                     dpipe_field_id2s(ctx, op_info->header_id,
6675                                      op_info->field_id,
6676                                      op_info->header_global));
6677        mapping = dpipe_mapping_get(ctx, op_info->header_id,
6678                                    op_info->field_id,
6679                                    op_info->header_global);
6680        if (mapping)
6681                print_string(PRINT_ANY, "mapping", " mapping %s", mapping);
6682}
6683
6684static int dpipe_match_parse(struct dpipe_match *match,
6685                             struct nlattr *nl)
6686
6687{
6688        struct nlattr *nla_match[DEVLINK_ATTR_MAX + 1] = {};
6689        int err;
6690
6691        err = mnl_attr_parse_nested(nl, attr_cb, nla_match);
6692        if (err != MNL_CB_OK)
6693                return -EINVAL;
6694
6695        if (!nla_match[DEVLINK_ATTR_DPIPE_MATCH_TYPE] ||
6696            !nla_match[DEVLINK_ATTR_DPIPE_HEADER_INDEX] ||
6697            !nla_match[DEVLINK_ATTR_DPIPE_HEADER_ID] ||
6698            !nla_match[DEVLINK_ATTR_DPIPE_FIELD_ID]) {
6699                return -EINVAL;
6700        }
6701
6702        match->type = mnl_attr_get_u32(nla_match[DEVLINK_ATTR_DPIPE_MATCH_TYPE]);
6703        match->info.header_id = mnl_attr_get_u32(nla_match[DEVLINK_ATTR_DPIPE_HEADER_ID]);
6704        match->info.field_id = mnl_attr_get_u32(nla_match[DEVLINK_ATTR_DPIPE_FIELD_ID]);
6705        match->info.header_global = !!mnl_attr_get_u8(nla_match[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL]);
6706
6707        return 0;
6708}
6709
6710static int dpipe_table_matches_show(struct dpipe_ctx *ctx,
6711                                    struct nlattr *nla_matches)
6712{
6713        struct nlattr *nla_match;
6714        struct dpipe_match match;
6715
6716        mnl_attr_for_each_nested(nla_match, nla_matches) {
6717                pr_out_entry_start(ctx->dl);
6718                if (dpipe_match_parse(&match, nla_match))
6719                        goto err_match_parse;
6720                pr_out_dpipe_match(&match, ctx);
6721                pr_out_entry_end(ctx->dl);
6722        }
6723        return 0;
6724
6725err_match_parse:
6726        pr_out_entry_end(ctx->dl);
6727        return -EINVAL;
6728}
6729
6730static struct resource *
6731resource_find(struct resources *resources, struct resource *resource,
6732              uint64_t resource_id)
6733{
6734        struct list_head *list_head;
6735
6736        if (!resource)
6737                list_head = &resources->resource_list;
6738        else
6739                list_head = &resource->resource_list;
6740
6741        list_for_each_entry(resource, list_head, list) {
6742                struct resource *child_resource;
6743
6744                if (resource->id == resource_id)
6745                        return resource;
6746
6747                child_resource = resource_find(resources, resource,
6748                                               resource_id);
6749                if (child_resource)
6750                        return child_resource;
6751        }
6752        return NULL;
6753}
6754
6755static void
6756resource_path_print(struct dl *dl, struct resources *resources,
6757                    uint64_t resource_id)
6758{
6759        struct resource *resource, *parent_resource;
6760        const char del[] = "/";
6761        int path_len = 0;
6762        char *path;
6763
6764        resource = resource_find(resources, NULL, resource_id);
6765        if (!resource)
6766                return;
6767
6768        for (parent_resource = resource; parent_resource;
6769             parent_resource = parent_resource->parent)
6770                path_len += strlen(parent_resource->name) + 1;
6771
6772        path_len++;
6773        path = calloc(1, path_len);
6774        if (!path)
6775                return;
6776
6777        path += path_len - 1;
6778        for (parent_resource = resource; parent_resource;
6779                parent_resource = parent_resource->parent) {
6780                path -= strlen(parent_resource->name);
6781                memcpy(path, parent_resource->name,
6782                       strlen(parent_resource->name));
6783                path -= strlen(del);
6784                memcpy(path, del, strlen(del));
6785        }
6786        check_indent_newline(dl);
6787        print_string(PRINT_ANY, "resource_path", "resource_path %s", path);
6788        free(path);
6789}
6790
6791static int dpipe_table_show(struct dpipe_ctx *ctx, struct nlattr *nl)
6792{
6793        struct nlattr *nla_table[DEVLINK_ATTR_MAX + 1] = {};
6794        struct dpipe_table *table;
6795        uint32_t resource_units;
6796        bool counters_enabled;
6797        bool resource_valid;
6798        uint32_t size;
6799        int err;
6800
6801        err = mnl_attr_parse_nested(nl, attr_cb, nla_table);
6802        if (err != MNL_CB_OK)
6803                return -EINVAL;
6804
6805        if (!nla_table[DEVLINK_ATTR_DPIPE_TABLE_NAME] ||
6806            !nla_table[DEVLINK_ATTR_DPIPE_TABLE_SIZE] ||
6807            !nla_table[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS] ||
6808            !nla_table[DEVLINK_ATTR_DPIPE_TABLE_MATCHES] ||
6809            !nla_table[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]) {
6810                return -EINVAL;
6811        }
6812
6813        table = dpipe_table_alloc();
6814        if (!table)
6815                return -ENOMEM;
6816
6817        table->name = strdup(mnl_attr_get_str(nla_table[DEVLINK_ATTR_DPIPE_TABLE_NAME]));
6818        size = mnl_attr_get_u32(nla_table[DEVLINK_ATTR_DPIPE_TABLE_SIZE]);
6819        counters_enabled = !!mnl_attr_get_u8(nla_table[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]);
6820
6821        resource_valid = nla_table[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID] &&
6822                         ctx->resources;
6823        if (resource_valid) {
6824                table->resource_id = mnl_attr_get_u64(nla_table[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID]);
6825                table->resource_valid = true;
6826        }
6827
6828        list_add_tail(&table->list, &ctx->tables->table_list);
6829        if (!ctx->print_tables)
6830                return 0;
6831
6832        check_indent_newline(ctx->dl);
6833        print_string(PRINT_ANY, "name", "name %s", table->name);
6834        print_uint(PRINT_ANY, "size", " size %u", size);
6835        print_bool(PRINT_ANY, "counters_enabled", " counters_enabled %s", counters_enabled);
6836
6837        if (resource_valid) {
6838                resource_units = mnl_attr_get_u32(nla_table[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS]);
6839                resource_path_print(ctx->dl, ctx->resources,
6840                                    table->resource_id);
6841                print_uint(PRINT_ANY, "resource_units", " resource_units %u",
6842                           resource_units);
6843        }
6844
6845        pr_out_array_start(ctx->dl, "match");
6846        if (dpipe_table_matches_show(ctx, nla_table[DEVLINK_ATTR_DPIPE_TABLE_MATCHES]))
6847                goto err_matches_show;
6848        pr_out_array_end(ctx->dl);
6849
6850        pr_out_array_start(ctx->dl, "action");
6851        if (dpipe_table_actions_show(ctx, nla_table[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS]))
6852                goto err_actions_show;
6853        pr_out_array_end(ctx->dl);
6854
6855        return 0;
6856
6857err_actions_show:
6858err_matches_show:
6859        pr_out_array_end(ctx->dl);
6860        return -EINVAL;
6861}
6862
6863static int dpipe_tables_show(struct dpipe_ctx *ctx, struct nlattr **tb)
6864{
6865        struct nlattr *nla_tables = tb[DEVLINK_ATTR_DPIPE_TABLES];
6866        struct nlattr *nla_table;
6867
6868        mnl_attr_for_each_nested(nla_table, nla_tables) {
6869                if (ctx->print_tables)
6870                        pr_out_handle_start_arr(ctx->dl, tb);
6871                if (dpipe_table_show(ctx, nla_table))
6872                        goto err_table_show;
6873                if (ctx->print_tables)
6874                        pr_out_handle_end(ctx->dl);
6875        }
6876        return 0;
6877
6878err_table_show:
6879        if (ctx->print_tables)
6880                pr_out_handle_end(ctx->dl);
6881        return -EINVAL;
6882}
6883
6884static int cmd_dpipe_table_show_cb(const struct nlmsghdr *nlh, void *data)
6885{
6886        struct dpipe_ctx *ctx = data;
6887        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
6888        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
6889
6890        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
6891        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
6892            !tb[DEVLINK_ATTR_DPIPE_TABLES])
6893                return MNL_CB_ERROR;
6894
6895        if (dpipe_tables_show(ctx, tb))
6896                return MNL_CB_ERROR;
6897        return MNL_CB_OK;
6898}
6899
6900static int cmd_resource_dump_cb(const struct nlmsghdr *nlh, void *data);
6901
6902static int cmd_dpipe_table_show(struct dl *dl)
6903{
6904        struct nlmsghdr *nlh;
6905        struct dpipe_ctx dpipe_ctx = {};
6906        struct resource_ctx resource_ctx = {};
6907        uint16_t flags = NLM_F_REQUEST;
6908        int err;
6909
6910        err = dl_argv_parse(dl, DL_OPT_HANDLE, DL_OPT_DPIPE_TABLE_NAME);
6911        if (err)
6912                return err;
6913
6914        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags);
6915
6916        err = dpipe_ctx_init(&dpipe_ctx, dl);
6917        if (err)
6918                return err;
6919
6920        dpipe_ctx.print_tables = true;
6921
6922        dl_opts_put(nlh, dl);
6923        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_dpipe_header_cb,
6924                                  &dpipe_ctx);
6925        if (err) {
6926                pr_err("error get headers %s\n", strerror(dpipe_ctx.err));
6927                goto err_headers_get;
6928        }
6929
6930        err = resource_ctx_init(&resource_ctx, dl);
6931        if (err)
6932                goto err_resource_ctx_init;
6933
6934        resource_ctx.print_resources = false;
6935        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RESOURCE_DUMP, flags);
6936        dl_opts_put(nlh, dl);
6937        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_resource_dump_cb,
6938                                  &resource_ctx);
6939        if (!err)
6940                dpipe_ctx.resources = resource_ctx.resources;
6941
6942        flags = NLM_F_REQUEST | NLM_F_ACK;
6943        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_DPIPE_TABLE_GET, flags);
6944        dl_opts_put(nlh, dl);
6945
6946        pr_out_section_start(dl, "table");
6947        mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_dpipe_table_show_cb, &dpipe_ctx);
6948        pr_out_section_end(dl);
6949
6950        resource_ctx_fini(&resource_ctx);
6951        dpipe_ctx_fini(&dpipe_ctx);
6952        return 0;
6953
6954err_resource_ctx_init:
6955err_headers_get:
6956        dpipe_ctx_fini(&dpipe_ctx);
6957        return err;
6958}
6959
6960static int cmd_dpipe_table_set(struct dl *dl)
6961{
6962        struct nlmsghdr *nlh;
6963        int err;
6964
6965        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
6966                               NLM_F_REQUEST | NLM_F_ACK);
6967
6968        err = dl_argv_parse_put(nlh, dl,
6969                                DL_OPT_HANDLE | DL_OPT_DPIPE_TABLE_NAME |
6970                                DL_OPT_DPIPE_TABLE_COUNTERS, 0);
6971        if (err)
6972                return err;
6973
6974        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
6975}
6976
6977enum dpipe_value_type {
6978        DPIPE_VALUE_TYPE_VALUE,
6979        DPIPE_VALUE_TYPE_MASK,
6980};
6981
6982static const char *
6983dpipe_value_type_e2s(enum dpipe_value_type type)
6984{
6985        switch (type) {
6986        case DPIPE_VALUE_TYPE_VALUE:
6987                return "value";
6988        case DPIPE_VALUE_TYPE_MASK:
6989                return "value_mask";
6990        default:
6991                return "<unknown>";
6992        }
6993}
6994
6995struct dpipe_field_printer {
6996        unsigned int field_id;
6997        void (*printer)(struct dpipe_ctx *, enum dpipe_value_type, void *);
6998};
6999
7000struct dpipe_header_printer {
7001        struct dpipe_field_printer *printers;
7002        unsigned int printers_count;
7003        unsigned int header_id;
7004};
7005
7006static void dpipe_field_printer_ipv4_addr(struct dpipe_ctx *ctx,
7007                                          enum dpipe_value_type type,
7008                                          void *value)
7009{
7010        struct in_addr ip_addr;
7011
7012        ip_addr.s_addr = htonl(*(uint32_t *)value);
7013        check_indent_newline(ctx->dl);
7014        print_string_name_value(dpipe_value_type_e2s(type), inet_ntoa(ip_addr));
7015}
7016
7017static void
7018dpipe_field_printer_ethernet_addr(struct dpipe_ctx *ctx,
7019                                  enum dpipe_value_type type,
7020                                  void *value)
7021{
7022        check_indent_newline(ctx->dl);
7023        print_string_name_value(dpipe_value_type_e2s(type),
7024                                ether_ntoa((struct ether_addr *)value));
7025}
7026
7027static void dpipe_field_printer_ipv6_addr(struct dpipe_ctx *ctx,
7028                                          enum dpipe_value_type type,
7029                                          void *value)
7030{
7031        char str[INET6_ADDRSTRLEN];
7032
7033        inet_ntop(AF_INET6, value, str, INET6_ADDRSTRLEN);
7034        check_indent_newline(ctx->dl);
7035        print_string_name_value(dpipe_value_type_e2s(type), str);
7036}
7037
7038static struct dpipe_field_printer dpipe_field_printers_ipv4[] = {
7039        {
7040                .printer = dpipe_field_printer_ipv4_addr,
7041                .field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP,
7042        }
7043};
7044
7045static struct dpipe_header_printer dpipe_header_printer_ipv4  = {
7046        .printers = dpipe_field_printers_ipv4,
7047        .printers_count = ARRAY_SIZE(dpipe_field_printers_ipv4),
7048        .header_id = DEVLINK_DPIPE_HEADER_IPV4,
7049};
7050
7051static struct dpipe_field_printer dpipe_field_printers_ethernet[] = {
7052        {
7053                .printer = dpipe_field_printer_ethernet_addr,
7054                .field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC,
7055        },
7056};
7057
7058static struct dpipe_header_printer dpipe_header_printer_ethernet = {
7059        .printers = dpipe_field_printers_ethernet,
7060        .printers_count = ARRAY_SIZE(dpipe_field_printers_ethernet),
7061        .header_id = DEVLINK_DPIPE_HEADER_ETHERNET,
7062};
7063
7064static struct dpipe_field_printer dpipe_field_printers_ipv6[] = {
7065        {
7066                .printer = dpipe_field_printer_ipv6_addr,
7067                .field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP,
7068        }
7069};
7070
7071static struct dpipe_header_printer dpipe_header_printer_ipv6 = {
7072        .printers = dpipe_field_printers_ipv6,
7073        .printers_count = ARRAY_SIZE(dpipe_field_printers_ipv6),
7074        .header_id = DEVLINK_DPIPE_HEADER_IPV6,
7075};
7076
7077static struct dpipe_header_printer *dpipe_header_printers[] = {
7078        &dpipe_header_printer_ipv4,
7079        &dpipe_header_printer_ethernet,
7080        &dpipe_header_printer_ipv6,
7081};
7082
7083static int dpipe_print_prot_header(struct dpipe_ctx *ctx,
7084                                   struct dpipe_op_info *info,
7085                                   enum dpipe_value_type type,
7086                                   void *value)
7087{
7088        unsigned int header_printers_count = ARRAY_SIZE(dpipe_header_printers);
7089        struct dpipe_header_printer *header_printer;
7090        struct dpipe_field_printer *field_printer;
7091        unsigned int field_printers_count;
7092        int j;
7093        int i;
7094
7095        for (i = 0; i < header_printers_count; i++) {
7096                header_printer = dpipe_header_printers[i];
7097                if (header_printer->header_id != info->header_id)
7098                        continue;
7099                field_printers_count = header_printer->printers_count;
7100                for (j = 0; j < field_printers_count; j++) {
7101                        field_printer = &header_printer->printers[j];
7102                        if (field_printer->field_id != info->field_id)
7103                                continue;
7104                        field_printer->printer(ctx, type, value);
7105                        return 0;
7106                }
7107        }
7108
7109        return -EINVAL;
7110}
7111
7112static void __pr_out_entry_value(struct dpipe_ctx *ctx,
7113                                 void *value,
7114                                 unsigned int value_len,
7115                                 struct dpipe_op_info *info,
7116                                 enum dpipe_value_type type)
7117{
7118        if (info->header_global &&
7119            !dpipe_print_prot_header(ctx, info, type, value))
7120                return;
7121
7122        if (value_len == sizeof(uint32_t)) {
7123                uint32_t *value_32 = value;
7124
7125                check_indent_newline(ctx->dl);
7126                print_uint_name_value(dpipe_value_type_e2s(type), *value_32);
7127        }
7128}
7129
7130static void pr_out_dpipe_entry_value(struct dpipe_ctx *ctx,
7131                                     struct nlattr **nla_match_value,
7132                                     struct dpipe_op_info *info)
7133{
7134        void *value, *value_mask;
7135        uint32_t value_mapping;
7136        uint16_t value_len;
7137        bool mask, mapping;
7138
7139        mask = !!nla_match_value[DEVLINK_ATTR_DPIPE_VALUE_MASK];
7140        mapping = !!nla_match_value[DEVLINK_ATTR_DPIPE_VALUE_MAPPING];
7141
7142        value_len = mnl_attr_get_payload_len(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]);
7143        value = mnl_attr_get_payload(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]);
7144
7145        if (mapping) {
7146                value_mapping = mnl_attr_get_u32(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE_MAPPING]);
7147                check_indent_newline(ctx->dl);
7148                print_uint(PRINT_ANY, "mapping_value", "mapping_value %u", value_mapping);
7149        }
7150
7151        if (mask) {
7152                value_mask = mnl_attr_get_payload(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]);
7153                __pr_out_entry_value(ctx, value_mask, value_len, info,
7154                                     DPIPE_VALUE_TYPE_MASK);
7155        }
7156
7157        __pr_out_entry_value(ctx, value, value_len, info, DPIPE_VALUE_TYPE_VALUE);
7158}
7159
7160static int dpipe_entry_match_value_show(struct dpipe_ctx *ctx,
7161                                        struct nlattr *nl)
7162{
7163        struct nlattr *nla_match_value[DEVLINK_ATTR_MAX + 1] = {};
7164        struct dpipe_match match;
7165        int err;
7166
7167        err = mnl_attr_parse_nested(nl, attr_cb, nla_match_value);
7168        if (err != MNL_CB_OK)
7169                return -EINVAL;
7170
7171        if (!nla_match_value[DEVLINK_ATTR_DPIPE_MATCH] ||
7172            !nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]) {
7173                return -EINVAL;
7174        }
7175
7176        pr_out_entry_start(ctx->dl);
7177        if (dpipe_match_parse(&match,
7178                              nla_match_value[DEVLINK_ATTR_DPIPE_MATCH]))
7179                goto err_match_parse;
7180        pr_out_dpipe_match(&match, ctx);
7181        pr_out_dpipe_entry_value(ctx, nla_match_value, &match.info);
7182        pr_out_entry_end(ctx->dl);
7183
7184        return 0;
7185
7186err_match_parse:
7187        pr_out_entry_end(ctx->dl);
7188        return -EINVAL;
7189}
7190
7191static int dpipe_entry_action_value_show(struct dpipe_ctx *ctx,
7192                                         struct nlattr *nl)
7193{
7194        struct nlattr *nla_action_value[DEVLINK_ATTR_MAX + 1] = {};
7195        struct dpipe_action action;
7196        int err;
7197
7198        err = mnl_attr_parse_nested(nl, attr_cb, nla_action_value);
7199        if (err != MNL_CB_OK)
7200                return -EINVAL;
7201
7202        if (!nla_action_value[DEVLINK_ATTR_DPIPE_ACTION] ||
7203            !nla_action_value[DEVLINK_ATTR_DPIPE_VALUE]) {
7204                return -EINVAL;
7205        }
7206
7207        pr_out_entry_start(ctx->dl);
7208        if (dpipe_action_parse(&action,
7209                               nla_action_value[DEVLINK_ATTR_DPIPE_ACTION]))
7210                goto err_action_parse;
7211        pr_out_dpipe_action(&action, ctx);
7212        pr_out_dpipe_entry_value(ctx, nla_action_value, &action.info);
7213        pr_out_entry_end(ctx->dl);
7214
7215        return 0;
7216
7217err_action_parse:
7218        pr_out_entry_end(ctx->dl);
7219        return -EINVAL;
7220}
7221
7222static int
7223dpipe_tables_action_values_show(struct dpipe_ctx *ctx,
7224                                struct nlattr *nla_action_values)
7225{
7226        struct nlattr *nla_action_value;
7227
7228        mnl_attr_for_each_nested(nla_action_value, nla_action_values) {
7229                if (dpipe_entry_action_value_show(ctx, nla_action_value))
7230                        return -EINVAL;
7231        }
7232        return 0;
7233}
7234
7235static int
7236dpipe_tables_match_values_show(struct dpipe_ctx *ctx,
7237                               struct nlattr *nla_match_values)
7238{
7239        struct nlattr *nla_match_value;
7240
7241        mnl_attr_for_each_nested(nla_match_value, nla_match_values) {
7242                if (dpipe_entry_match_value_show(ctx, nla_match_value))
7243                        return -EINVAL;
7244        }
7245        return 0;
7246}
7247
7248static int dpipe_entry_show(struct dpipe_ctx *ctx, struct nlattr *nl)
7249{
7250        struct nlattr *nla_entry[DEVLINK_ATTR_MAX + 1] = {};
7251        uint32_t entry_index;
7252        uint64_t counter;
7253        int err;
7254
7255        err = mnl_attr_parse_nested(nl, attr_cb, nla_entry);
7256        if (err != MNL_CB_OK)
7257                return -EINVAL;
7258
7259        if (!nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_INDEX] ||
7260            !nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES] ||
7261            !nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES]) {
7262                return -EINVAL;
7263        }
7264
7265        check_indent_newline(ctx->dl);
7266        entry_index = mnl_attr_get_u32(nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_INDEX]);
7267        print_uint(PRINT_ANY, "index", "index %u", entry_index);
7268
7269        if (nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER]) {
7270                counter = mnl_attr_get_u64(nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER]);
7271                print_uint(PRINT_ANY, "counter", " counter %u", counter);
7272        }
7273
7274        pr_out_array_start(ctx->dl, "match_value");
7275        if (dpipe_tables_match_values_show(ctx,
7276                                           nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES]))
7277                goto err_match_values_show;
7278        pr_out_array_end(ctx->dl);
7279
7280        pr_out_array_start(ctx->dl, "action_value");
7281        if (dpipe_tables_action_values_show(ctx,
7282                                            nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES]))
7283                goto err_action_values_show;
7284        pr_out_array_end(ctx->dl);
7285        return 0;
7286
7287err_action_values_show:
7288err_match_values_show:
7289        pr_out_array_end(ctx->dl);
7290        return -EINVAL;
7291}
7292
7293static int dpipe_table_entries_show(struct dpipe_ctx *ctx, struct nlattr **tb)
7294{
7295        struct nlattr *nla_entries = tb[DEVLINK_ATTR_DPIPE_ENTRIES];
7296        struct nlattr *nla_entry;
7297
7298        mnl_attr_for_each_nested(nla_entry, nla_entries) {
7299                pr_out_handle_start_arr(ctx->dl, tb);
7300                if (dpipe_entry_show(ctx, nla_entry))
7301                        goto err_entry_show;
7302                pr_out_handle_end(ctx->dl);
7303        }
7304        return 0;
7305
7306err_entry_show:
7307        pr_out_handle_end(ctx->dl);
7308        return -EINVAL;
7309}
7310
7311static int cmd_dpipe_table_entry_dump_cb(const struct nlmsghdr *nlh, void *data)
7312{
7313        struct dpipe_ctx *ctx = data;
7314        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
7315        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
7316
7317        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
7318        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
7319            !tb[DEVLINK_ATTR_DPIPE_ENTRIES])
7320                return MNL_CB_ERROR;
7321
7322        if (dpipe_table_entries_show(ctx, tb))
7323                return MNL_CB_ERROR;
7324        return MNL_CB_OK;
7325}
7326
7327static int cmd_dpipe_table_dump(struct dl *dl)
7328{
7329        struct nlmsghdr *nlh;
7330        struct dpipe_ctx ctx = {};
7331        uint16_t flags = NLM_F_REQUEST;
7332        int err;
7333
7334        err = dpipe_ctx_init(&ctx, dl);
7335        if (err)
7336                return err;
7337
7338        err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_DPIPE_TABLE_NAME, 0);
7339        if (err)
7340                goto out;
7341
7342        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags);
7343        dl_opts_put(nlh, dl);
7344        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_dpipe_header_cb, &ctx);
7345        if (err) {
7346                pr_err("error get headers %s\n", strerror(ctx.err));
7347                goto out;
7348        }
7349
7350        flags = NLM_F_REQUEST | NLM_F_ACK;
7351        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_DPIPE_ENTRIES_GET, flags);
7352        dl_opts_put(nlh, dl);
7353
7354        pr_out_section_start(dl, "table_entry");
7355        mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_dpipe_table_entry_dump_cb, &ctx);
7356        pr_out_section_end(dl);
7357out:
7358        dpipe_ctx_fini(&ctx);
7359        return err;
7360}
7361
7362static int cmd_dpipe_table(struct dl *dl)
7363{
7364        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
7365                cmd_dpipe_help();
7366                return 0;
7367        } else if (dl_argv_match(dl, "show")) {
7368                dl_arg_inc(dl);
7369                return cmd_dpipe_table_show(dl);
7370        } else if (dl_argv_match(dl, "set")) {
7371                dl_arg_inc(dl);
7372                return cmd_dpipe_table_set(dl);
7373        }  else if (dl_argv_match(dl, "dump")) {
7374                dl_arg_inc(dl);
7375                return cmd_dpipe_table_dump(dl);
7376        }
7377        pr_err("Command \"%s\" not found\n", dl_argv(dl));
7378        return -ENOENT;
7379}
7380
7381static int cmd_dpipe(struct dl *dl)
7382{
7383        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
7384                cmd_dpipe_help();
7385                return 0;
7386        } else if (dl_argv_match(dl, "header")) {
7387                dl_arg_inc(dl);
7388                return cmd_dpipe_header(dl);
7389        } else if (dl_argv_match(dl, "table")) {
7390                dl_arg_inc(dl);
7391                return cmd_dpipe_table(dl);
7392        }
7393        pr_err("Command \"%s\" not found\n", dl_argv(dl));
7394        return -ENOENT;
7395}
7396
7397static int
7398resource_parse(struct resource_ctx *ctx, struct resource *resource,
7399               struct nlattr **nla_resource)
7400{
7401        if (!nla_resource[DEVLINK_ATTR_RESOURCE_NAME] ||
7402            !nla_resource[DEVLINK_ATTR_RESOURCE_SIZE] ||
7403            !nla_resource[DEVLINK_ATTR_RESOURCE_ID] ||
7404            !nla_resource[DEVLINK_ATTR_RESOURCE_UNIT] ||
7405            !nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_MIN] ||
7406            !nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_MAX] ||
7407            !nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_GRAN]) {
7408                return -EINVAL;
7409        }
7410
7411        resource->name = strdup(mnl_attr_get_str(nla_resource[DEVLINK_ATTR_RESOURCE_NAME]));
7412        resource->size = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE]);
7413        resource->id = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_ID]);
7414        resource->unit = mnl_attr_get_u8(nla_resource[DEVLINK_ATTR_RESOURCE_UNIT]);
7415        resource->size_min = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_MIN]);
7416        resource->size_max = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_MAX]);
7417        resource->size_gran = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_GRAN]);
7418
7419        if (nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_NEW])
7420                resource->size_new = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_NEW]);
7421        else
7422                resource->size_new = resource->size;
7423
7424        if (nla_resource[DEVLINK_ATTR_RESOURCE_OCC]) {
7425                resource->size_occ = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_OCC]);
7426                resource->occ_valid = true;
7427        }
7428
7429        if (resource->size_new != resource->size)
7430                ctx->pending_change = true;
7431
7432        return 0;
7433}
7434
7435static int
7436resource_get(struct resource_ctx *ctx, struct resource *resource,
7437             struct resource *parent_resource, struct nlattr *nl)
7438{
7439        struct nlattr *nla_resource[DEVLINK_ATTR_MAX + 1] = {};
7440        struct nlattr *nla_child_resource;
7441        struct nlattr *nla_resources;
7442        bool top = false;
7443        int err;
7444
7445        if (!resource) {
7446                nla_resources = nl;
7447                top = true;
7448                goto out;
7449        }
7450
7451        err = mnl_attr_parse_nested(nl, attr_cb, nla_resource);
7452        if (err != MNL_CB_OK)
7453                return -EINVAL;
7454
7455        err = resource_parse(ctx, resource, nla_resource);
7456        if (err)
7457                return err;
7458
7459        resource->parent = parent_resource;
7460        if (!nla_resource[DEVLINK_ATTR_RESOURCE_LIST])
7461                return 0;
7462
7463        resource->size_valid = !!mnl_attr_get_u8(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_VALID]);
7464        nla_resources = nla_resource[DEVLINK_ATTR_RESOURCE_LIST];
7465out:
7466        mnl_attr_for_each_nested(nla_child_resource, nla_resources) {
7467                struct resource *child_resource;
7468                struct list_head *list;
7469
7470                child_resource = resource_alloc();
7471                if (!child_resource)
7472                        return -ENOMEM;
7473
7474                if (top)
7475                        list = &ctx->resources->resource_list;
7476                else
7477                        list = &resource->resource_list;
7478
7479                list_add_tail(&child_resource->list, list);
7480                err = resource_get(ctx, child_resource, resource,
7481                                   nla_child_resource);
7482                if (err)
7483                        return err;
7484        }
7485
7486        return 0;
7487}
7488
7489static const char *resource_unit_str_get(enum devlink_resource_unit unit)
7490{
7491        switch (unit) {
7492        case DEVLINK_RESOURCE_UNIT_ENTRY: return "entry";
7493        default: return "<unknown unit>";
7494        }
7495}
7496
7497static void resource_show(struct resource *resource,
7498                          struct resource_ctx *ctx)
7499{
7500        struct resource *child_resource;
7501        struct dpipe_table *table;
7502        struct dl *dl = ctx->dl;
7503        bool array = false;
7504
7505        check_indent_newline(dl);
7506        print_string(PRINT_ANY, "name", "name %s", resource->name);
7507        if (dl->verbose)
7508                resource_path_print(dl, ctx->resources, resource->id);
7509        pr_out_u64(dl, "size", resource->size);
7510        if (resource->size != resource->size_new)
7511                pr_out_u64(dl, "size_new", resource->size_new);
7512        if (resource->occ_valid)
7513                print_uint(PRINT_ANY, "occ", " occ %u",  resource->size_occ);
7514        print_string(PRINT_ANY, "unit", " unit %s",
7515                     resource_unit_str_get(resource->unit));
7516
7517        if (resource->size_min != resource->size_max) {
7518                print_uint(PRINT_ANY, "size_min", " size_min %u",
7519                           resource->size_min);
7520                pr_out_u64(dl, "size_max", resource->size_max);
7521                print_uint(PRINT_ANY, "size_gran", " size_gran %u",
7522                           resource->size_gran);
7523        }
7524
7525        list_for_each_entry(table, &ctx->tables->table_list, list)
7526                if (table->resource_id == resource->id &&
7527                    table->resource_valid)
7528                        array = true;
7529
7530        if (array)
7531                pr_out_array_start(dl, "dpipe_tables");
7532        else
7533                print_string(PRINT_ANY, "dpipe_tables", " dpipe_tables none",
7534                             "none");
7535
7536        list_for_each_entry(table, &ctx->tables->table_list, list) {
7537                if (table->resource_id != resource->id ||
7538                    !table->resource_valid)
7539                        continue;
7540                pr_out_entry_start(dl);
7541                check_indent_newline(dl);
7542                print_string(PRINT_ANY, "table_name", "table_name %s",
7543                             table->name);
7544                pr_out_entry_end(dl);
7545        }
7546        if (array)
7547                pr_out_array_end(dl);
7548
7549        if (list_empty(&resource->resource_list))
7550                return;
7551
7552        if (ctx->pending_change) {
7553                check_indent_newline(dl);
7554                print_string(PRINT_ANY, "size_valid", "size_valid %s",
7555                             resource->size_valid ? "true" : "false");
7556        }
7557        pr_out_array_start(dl, "resources");
7558        list_for_each_entry(child_resource, &resource->resource_list, list) {
7559                pr_out_entry_start(dl);
7560                resource_show(child_resource, ctx);
7561                pr_out_entry_end(dl);
7562        }
7563        pr_out_array_end(dl);
7564}
7565
7566static void
7567resources_show(struct resource_ctx *ctx, struct nlattr **tb)
7568{
7569        struct resources *resources = ctx->resources;
7570        struct resource *resource;
7571
7572        list_for_each_entry(resource, &resources->resource_list, list) {
7573                pr_out_handle_start_arr(ctx->dl, tb);
7574                resource_show(resource, ctx);
7575                pr_out_handle_end(ctx->dl);
7576        }
7577}
7578
7579static int resources_get(struct resource_ctx *ctx, struct nlattr **tb)
7580{
7581        return resource_get(ctx, NULL, NULL, tb[DEVLINK_ATTR_RESOURCE_LIST]);
7582}
7583
7584static int cmd_resource_dump_cb(const struct nlmsghdr *nlh, void *data)
7585{
7586        struct resource_ctx *ctx = data;
7587        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
7588        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
7589        int err;
7590
7591        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
7592        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
7593            !tb[DEVLINK_ATTR_RESOURCE_LIST])
7594                return MNL_CB_ERROR;
7595
7596        err = resources_get(ctx, tb);
7597        if (err) {
7598                ctx->err = err;
7599                return MNL_CB_ERROR;
7600        }
7601
7602        if (ctx->print_resources)
7603                resources_show(ctx, tb);
7604
7605        return MNL_CB_OK;
7606}
7607
7608static int cmd_resource_show(struct dl *dl)
7609{
7610        struct nlmsghdr *nlh;
7611        struct dpipe_ctx dpipe_ctx = {};
7612        struct resource_ctx resource_ctx = {};
7613        int err;
7614
7615        err = dl_argv_parse(dl, DL_OPT_HANDLE, 0);
7616        if (err)
7617                return err;
7618
7619        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_DPIPE_TABLE_GET,
7620                               NLM_F_REQUEST);
7621        dl_opts_put(nlh, dl);
7622
7623        err = dpipe_ctx_init(&dpipe_ctx, dl);
7624        if (err)
7625                return err;
7626
7627        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_dpipe_table_show_cb,
7628                                  &dpipe_ctx);
7629        if (err) {
7630                pr_err("error get tables %s\n", strerror(dpipe_ctx.err));
7631                goto out;
7632        }
7633
7634        err = resource_ctx_init(&resource_ctx, dl);
7635        if (err)
7636                goto out;
7637
7638        resource_ctx.print_resources = true;
7639        resource_ctx.tables = dpipe_ctx.tables;
7640        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RESOURCE_DUMP,
7641                               NLM_F_REQUEST | NLM_F_ACK);
7642        dl_opts_put(nlh, dl);
7643        pr_out_section_start(dl, "resources");
7644        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_resource_dump_cb,
7645                                  &resource_ctx);
7646        pr_out_section_end(dl);
7647        resource_ctx_fini(&resource_ctx);
7648out:
7649        dpipe_ctx_fini(&dpipe_ctx);
7650        return err;
7651}
7652
7653static void cmd_resource_help(void)
7654{
7655        pr_err("Usage: devlink resource show DEV\n"
7656               "       devlink resource set DEV path PATH size SIZE\n");
7657}
7658
7659static struct resource *
7660resource_find_by_name(struct list_head *list, char *name)
7661{
7662        struct resource *resource;
7663
7664        list_for_each_entry(resource, list, list) {
7665                if (!strcmp(resource->name, name))
7666                        return resource;
7667        }
7668        return NULL;
7669}
7670
7671static int
7672resource_path_parse(struct resource_ctx *ctx, const char *resource_path,
7673                    uint32_t *p_resource_id, bool *p_resource_valid)
7674{
7675        struct resource *resource;
7676        uint32_t resource_id = 0;
7677        char *resource_path_dup;
7678        struct list_head *list;
7679        const char del[] = "/";
7680        char *resource_name;
7681
7682        resource_path_dup = strdup(resource_path);
7683        list = &ctx->resources->resource_list;
7684        resource_name = strtok(resource_path_dup, del);
7685        while (resource_name != NULL) {
7686                resource = resource_find_by_name(list, resource_name);
7687                if (!resource)
7688                        goto err_resource_lookup;
7689
7690                list = &resource->resource_list;
7691                resource_name = strtok(NULL, del);
7692                resource_id = resource->id;
7693        }
7694        free(resource_path_dup);
7695        *p_resource_valid = true;
7696        *p_resource_id = resource_id;
7697        return 0;
7698
7699err_resource_lookup:
7700        free(resource_path_dup);
7701        return -EINVAL;
7702}
7703
7704static int cmd_resource_set(struct dl *dl)
7705{
7706        struct nlmsghdr *nlh;
7707        struct resource_ctx ctx = {};
7708        int err;
7709
7710        err = resource_ctx_init(&ctx, dl);
7711        if (err)
7712                return err;
7713
7714        ctx.print_resources = false;
7715        err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_RESOURCE_PATH |
7716                            DL_OPT_RESOURCE_SIZE, 0);
7717        if (err)
7718                goto out;
7719
7720        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RESOURCE_DUMP,
7721                               NLM_F_REQUEST);
7722        dl_opts_put(nlh, dl);
7723        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_resource_dump_cb, &ctx);
7724        if (err) {
7725                pr_err("error getting resources %s\n", strerror(ctx.err));
7726                goto out;
7727        }
7728
7729        err = resource_path_parse(&ctx, dl->opts.resource_path,
7730                                  &dl->opts.resource_id,
7731                                  &dl->opts.resource_id_valid);
7732        if (err) {
7733                pr_err("error parsing resource path %s\n", strerror(-err));
7734                goto out;
7735        }
7736
7737        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RESOURCE_SET,
7738                               NLM_F_REQUEST | NLM_F_ACK);
7739
7740        dl_opts_put(nlh, dl);
7741        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
7742out:
7743        resource_ctx_fini(&ctx);
7744        return err;
7745}
7746
7747static int cmd_resource(struct dl *dl)
7748{
7749        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
7750                cmd_resource_help();
7751                return 0;
7752        } else if (dl_argv_match(dl, "show")) {
7753                dl_arg_inc(dl);
7754                return cmd_resource_show(dl);
7755        } else if (dl_argv_match(dl, "set")) {
7756                dl_arg_inc(dl);
7757                return cmd_resource_set(dl);
7758        }
7759        pr_err("Command \"%s\" not found\n", dl_argv(dl));
7760        return -ENOENT;
7761}
7762
7763static void pr_out_region_handle_start(struct dl *dl, struct nlattr **tb)
7764{
7765        const char *bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
7766        const char *dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
7767        const char *region_name = mnl_attr_get_str(tb[DEVLINK_ATTR_REGION_NAME]);
7768        char buf[256];
7769
7770        sprintf(buf, "%s/%s/%s", bus_name, dev_name, region_name);
7771        if (dl->json_output)
7772                open_json_object(buf);
7773        else
7774                pr_out("%s:", buf);
7775}
7776
7777static void pr_out_region_handle_end(struct dl *dl)
7778{
7779        if (dl->json_output)
7780                close_json_object();
7781        else
7782                pr_out("\n");
7783}
7784
7785static void pr_out_region_snapshots_start(struct dl *dl, bool array)
7786{
7787        __pr_out_indent_newline(dl);
7788        if (dl->json_output)
7789                open_json_array(PRINT_JSON, "snapshot");
7790        else
7791                pr_out("snapshot %s", array ? "[" : "");
7792}
7793
7794static void pr_out_region_snapshots_end(struct dl *dl, bool array)
7795{
7796        if (dl->json_output)
7797                close_json_array(PRINT_JSON, NULL);
7798        else if (array)
7799                pr_out("]");
7800}
7801
7802static void pr_out_region_snapshots_id(struct dl *dl, struct nlattr **tb, int index)
7803{
7804        uint32_t snapshot_id;
7805
7806        if (!tb[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
7807                return;
7808
7809        snapshot_id = mnl_attr_get_u32(tb[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
7810
7811        if (dl->json_output)
7812                print_uint(PRINT_JSON, NULL, NULL, snapshot_id);
7813        else
7814                pr_out("%s%u", index ? " " : "", snapshot_id);
7815}
7816
7817static void pr_out_snapshots(struct dl *dl, struct nlattr **tb)
7818{
7819        struct nlattr *tb_snapshot[DEVLINK_ATTR_MAX + 1] = {};
7820        struct nlattr *nla_sanpshot;
7821        int err, index = 0;
7822
7823        pr_out_region_snapshots_start(dl, true);
7824        mnl_attr_for_each_nested(nla_sanpshot, tb[DEVLINK_ATTR_REGION_SNAPSHOTS]) {
7825                err = mnl_attr_parse_nested(nla_sanpshot, attr_cb, tb_snapshot);
7826                if (err != MNL_CB_OK)
7827                        return;
7828                pr_out_region_snapshots_id(dl, tb_snapshot, index++);
7829        }
7830        pr_out_region_snapshots_end(dl, true);
7831}
7832
7833static void pr_out_snapshot(struct dl *dl, struct nlattr **tb)
7834{
7835        pr_out_region_snapshots_start(dl, false);
7836        pr_out_region_snapshots_id(dl, tb, 0);
7837        pr_out_region_snapshots_end(dl, false);
7838}
7839
7840static void pr_out_region(struct dl *dl, struct nlattr **tb)
7841{
7842        pr_out_region_handle_start(dl, tb);
7843
7844        if (tb[DEVLINK_ATTR_REGION_SIZE])
7845                pr_out_u64(dl, "size",
7846                           mnl_attr_get_u64(tb[DEVLINK_ATTR_REGION_SIZE]));
7847
7848        if (tb[DEVLINK_ATTR_REGION_SNAPSHOTS])
7849                pr_out_snapshots(dl, tb);
7850
7851        if (tb[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
7852                pr_out_snapshot(dl, tb);
7853
7854        if (tb[DEVLINK_ATTR_REGION_MAX_SNAPSHOTS])
7855                pr_out_u64(dl, "max",
7856                           mnl_attr_get_u32(tb[DEVLINK_ATTR_REGION_MAX_SNAPSHOTS]));
7857
7858        pr_out_region_handle_end(dl);
7859}
7860
7861static int cmd_region_show_cb(const struct nlmsghdr *nlh, void *data)
7862{
7863        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
7864        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
7865        struct dl *dl = data;
7866
7867        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
7868        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
7869            !tb[DEVLINK_ATTR_REGION_NAME] || !tb[DEVLINK_ATTR_REGION_SIZE])
7870                return MNL_CB_ERROR;
7871
7872        pr_out_region(dl, tb);
7873
7874        return MNL_CB_OK;
7875}
7876
7877static int cmd_region_show(struct dl *dl)
7878{
7879        struct nlmsghdr *nlh;
7880        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
7881        int err;
7882
7883        if (dl_argc(dl) == 0)
7884                flags |= NLM_F_DUMP;
7885
7886        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_REGION_GET, flags);
7887
7888        if (dl_argc(dl) > 0) {
7889                err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION, 0);
7890                if (err)
7891                        return err;
7892        }
7893
7894        pr_out_section_start(dl, "regions");
7895        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_region_show_cb, dl);
7896        pr_out_section_end(dl);
7897        return err;
7898}
7899
7900static int cmd_region_snapshot_del(struct dl *dl)
7901{
7902        struct nlmsghdr *nlh;
7903        int err;
7904
7905        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_REGION_DEL,
7906                               NLM_F_REQUEST | NLM_F_ACK);
7907
7908        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION |
7909                                DL_OPT_REGION_SNAPSHOT_ID, 0);
7910        if (err)
7911                return err;
7912
7913        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
7914}
7915
7916static int cmd_region_read_cb(const struct nlmsghdr *nlh, void *data)
7917{
7918        struct nlattr *nla_entry, *nla_chunk_data, *nla_chunk_addr;
7919        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
7920        struct nlattr *tb_field[DEVLINK_ATTR_MAX + 1] = {};
7921        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
7922        struct dl *dl = data;
7923        int err;
7924
7925        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
7926        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
7927            !tb[DEVLINK_ATTR_REGION_CHUNKS])
7928                return MNL_CB_ERROR;
7929
7930        mnl_attr_for_each_nested(nla_entry, tb[DEVLINK_ATTR_REGION_CHUNKS]) {
7931                err = mnl_attr_parse_nested(nla_entry, attr_cb, tb_field);
7932                if (err != MNL_CB_OK)
7933                        return MNL_CB_ERROR;
7934
7935                nla_chunk_data = tb_field[DEVLINK_ATTR_REGION_CHUNK_DATA];
7936                if (!nla_chunk_data)
7937                        continue;
7938
7939                nla_chunk_addr = tb_field[DEVLINK_ATTR_REGION_CHUNK_ADDR];
7940                if (!nla_chunk_addr)
7941                        continue;
7942
7943                pr_out_region_chunk(dl, mnl_attr_get_payload(nla_chunk_data),
7944                                    mnl_attr_get_payload_len(nla_chunk_data),
7945                                    mnl_attr_get_u64(nla_chunk_addr));
7946        }
7947        return MNL_CB_OK;
7948}
7949
7950static int cmd_region_dump(struct dl *dl)
7951{
7952        struct nlmsghdr *nlh;
7953        int err;
7954
7955        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_REGION_READ,
7956                               NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
7957
7958        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION |
7959                                DL_OPT_REGION_SNAPSHOT_ID, 0);
7960        if (err)
7961                return err;
7962
7963        pr_out_section_start(dl, "dump");
7964        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_region_read_cb, dl);
7965        pr_out_section_end(dl);
7966        if (!dl->json_output)
7967                pr_out("\n");
7968        return err;
7969}
7970
7971static int cmd_region_read(struct dl *dl)
7972{
7973        struct nlmsghdr *nlh;
7974        int err;
7975
7976        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_REGION_READ,
7977                               NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
7978
7979        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION |
7980                                DL_OPT_REGION_ADDRESS | DL_OPT_REGION_LENGTH |
7981                                DL_OPT_REGION_SNAPSHOT_ID, 0);
7982        if (err)
7983                return err;
7984
7985        pr_out_section_start(dl, "read");
7986        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_region_read_cb, dl);
7987        pr_out_section_end(dl);
7988        if (!dl->json_output)
7989                pr_out("\n");
7990        return err;
7991}
7992
7993static int cmd_region_snapshot_new_cb(const struct nlmsghdr *nlh, void *data)
7994{
7995        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
7996        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
7997        struct dl *dl = data;
7998
7999        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
8000        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
8001            !tb[DEVLINK_ATTR_REGION_NAME] ||
8002            !tb[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
8003                return MNL_CB_ERROR;
8004
8005        pr_out_region(dl, tb);
8006
8007        return MNL_CB_OK;
8008}
8009
8010static int cmd_region_snapshot_new(struct dl *dl)
8011{
8012        struct nlmsghdr *nlh;
8013        int err;
8014
8015        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_REGION_NEW,
8016                               NLM_F_REQUEST | NLM_F_ACK);
8017
8018        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION,
8019                                DL_OPT_REGION_SNAPSHOT_ID);
8020        if (err)
8021                return err;
8022
8023        pr_out_section_start(dl, "regions");
8024        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_region_snapshot_new_cb, dl);
8025        pr_out_section_end(dl);
8026        return err;
8027}
8028
8029static void cmd_region_help(void)
8030{
8031        pr_err("Usage: devlink region show [ DEV/REGION ]\n");
8032        pr_err("       devlink region del DEV/REGION snapshot SNAPSHOT_ID\n");
8033        pr_err("       devlink region new DEV/REGION snapshot SNAPSHOT_ID\n");
8034        pr_err("       devlink region dump DEV/REGION [ snapshot SNAPSHOT_ID ]\n");
8035        pr_err("       devlink region read DEV/REGION [ snapshot SNAPSHOT_ID ] address ADDRESS length LENGTH\n");
8036}
8037
8038static int cmd_region(struct dl *dl)
8039{
8040        if (dl_no_arg(dl)) {
8041                return cmd_region_show(dl);
8042        } else if (dl_argv_match(dl, "help")) {
8043                cmd_region_help();
8044                return 0;
8045        } else if (dl_argv_match(dl, "show")) {
8046                dl_arg_inc(dl);
8047                return cmd_region_show(dl);
8048        } else if (dl_argv_match(dl, "del")) {
8049                dl_arg_inc(dl);
8050                return cmd_region_snapshot_del(dl);
8051        } else if (dl_argv_match(dl, "dump")) {
8052                dl_arg_inc(dl);
8053                return cmd_region_dump(dl);
8054        } else if (dl_argv_match(dl, "read")) {
8055                dl_arg_inc(dl);
8056                return cmd_region_read(dl);
8057        } else if (dl_argv_match(dl, "new")) {
8058                dl_arg_inc(dl);
8059                return cmd_region_snapshot_new(dl);
8060        }
8061        pr_err("Command \"%s\" not found\n", dl_argv(dl));
8062        return -ENOENT;
8063}
8064
8065static int cmd_health_set_params(struct dl *dl)
8066{
8067        struct nlmsghdr *nlh;
8068        int err;
8069
8070        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_SET,
8071                               NLM_F_REQUEST | NLM_F_ACK);
8072        err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_HANDLEP | DL_OPT_HEALTH_REPORTER_NAME,
8073                            DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD |
8074                            DL_OPT_HEALTH_REPORTER_AUTO_RECOVER |
8075                            DL_OPT_HEALTH_REPORTER_AUTO_DUMP);
8076        if (err)
8077                return err;
8078
8079        dl_opts_put(nlh, dl);
8080        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
8081}
8082
8083static int cmd_health_dump_clear(struct dl *dl)
8084{
8085        struct nlmsghdr *nlh;
8086        int err;
8087
8088        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR,
8089                               NLM_F_REQUEST | NLM_F_ACK);
8090
8091        err = dl_argv_parse_put(nlh, dl,
8092                                DL_OPT_HANDLE | DL_OPT_HANDLEP |
8093                                DL_OPT_HEALTH_REPORTER_NAME, 0);
8094        if (err)
8095                return err;
8096
8097        dl_opts_put(nlh, dl);
8098        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
8099}
8100
8101static int fmsg_value_show(struct dl *dl, int type, struct nlattr *nl_data)
8102{
8103        uint8_t *data;
8104        uint32_t len;
8105
8106        check_indent_newline(dl);
8107        switch (type) {
8108        case MNL_TYPE_FLAG:
8109                print_bool(PRINT_ANY, NULL, "%s", mnl_attr_get_u8(nl_data));
8110                break;
8111        case MNL_TYPE_U8:
8112                print_uint(PRINT_ANY, NULL, "%u", mnl_attr_get_u8(nl_data));
8113                break;
8114        case MNL_TYPE_U16:
8115                print_uint(PRINT_ANY, NULL, "%u", mnl_attr_get_u16(nl_data));
8116                break;
8117        case MNL_TYPE_U32:
8118                print_uint(PRINT_ANY, NULL, "%u", mnl_attr_get_u32(nl_data));
8119                break;
8120        case MNL_TYPE_U64:
8121                print_u64(PRINT_ANY, NULL, "%"PRIu64, mnl_attr_get_u64(nl_data));
8122                break;
8123        case MNL_TYPE_NUL_STRING:
8124                print_string(PRINT_ANY, NULL, "%s", mnl_attr_get_str(nl_data));
8125                break;
8126        case MNL_TYPE_BINARY:
8127                len = mnl_attr_get_payload_len(nl_data);
8128                data = mnl_attr_get_payload(nl_data);
8129                pr_out_binary_value(dl, data, len);
8130                break;
8131        default:
8132                return -EINVAL;
8133        }
8134        return MNL_CB_OK;
8135}
8136
8137static void pr_out_fmsg_name(struct dl *dl, char **name)
8138{
8139        if (!*name)
8140                return;
8141
8142        pr_out_name(dl, *name);
8143        free(*name);
8144        *name = NULL;
8145}
8146
8147struct nest_entry {
8148        int attr_type;
8149        struct list_head list;
8150};
8151
8152struct fmsg_cb_data {
8153        char *name;
8154        struct dl *dl;
8155        uint8_t value_type;
8156        struct list_head entry_list;
8157};
8158
8159static int cmd_fmsg_nest_queue(struct fmsg_cb_data *fmsg_data,
8160                               uint8_t *attr_value, bool insert)
8161{
8162        struct nest_entry *entry;
8163
8164        if (insert) {
8165                entry = malloc(sizeof(struct nest_entry));
8166                if (!entry)
8167                        return -ENOMEM;
8168
8169                entry->attr_type = *attr_value;
8170                list_add(&entry->list, &fmsg_data->entry_list);
8171        } else {
8172                if (list_empty(&fmsg_data->entry_list))
8173                        return MNL_CB_ERROR;
8174                entry = list_first_entry(&fmsg_data->entry_list,
8175                                         struct nest_entry, list);
8176                *attr_value = entry->attr_type;
8177                list_del(&entry->list);
8178                free(entry);
8179        }
8180        return MNL_CB_OK;
8181}
8182
8183static void pr_out_fmsg_group_start(struct dl *dl, char **name)
8184{
8185        __pr_out_newline();
8186        pr_out_fmsg_name(dl, name);
8187        __pr_out_newline();
8188        __pr_out_indent_inc();
8189}
8190
8191static void pr_out_fmsg_group_end(struct dl *dl)
8192{
8193        __pr_out_newline();
8194        __pr_out_indent_dec();
8195}
8196
8197static void pr_out_fmsg_start_object(struct dl *dl, char **name)
8198{
8199        if (dl->json_output) {
8200                pr_out_fmsg_name(dl, name);
8201                open_json_object(NULL);
8202        } else {
8203                pr_out_fmsg_group_start(dl, name);
8204        }
8205}
8206
8207static void pr_out_fmsg_end_object(struct dl *dl)
8208{
8209        if (dl->json_output)
8210                close_json_object();
8211        else
8212                pr_out_fmsg_group_end(dl);
8213}
8214
8215static void pr_out_fmsg_start_array(struct dl *dl, char **name)
8216{
8217        if (dl->json_output) {
8218                pr_out_fmsg_name(dl, name);
8219                open_json_array(PRINT_JSON, NULL);
8220        } else {
8221                pr_out_fmsg_group_start(dl, name);
8222        }
8223}
8224
8225static void pr_out_fmsg_end_array(struct dl *dl)
8226{
8227        if (dl->json_output)
8228                close_json_array(PRINT_JSON, NULL);
8229        else
8230                pr_out_fmsg_group_end(dl);
8231}
8232
8233static int cmd_fmsg_nest(struct fmsg_cb_data *fmsg_data, uint8_t nest_value,
8234                         bool start)
8235{
8236        struct dl *dl = fmsg_data->dl;
8237        uint8_t value = nest_value;
8238        int err;
8239
8240        err = cmd_fmsg_nest_queue(fmsg_data, &value, start);
8241        if (err != MNL_CB_OK)
8242                return err;
8243
8244        switch (value) {
8245        case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
8246                if (start)
8247                        pr_out_fmsg_start_object(dl, &fmsg_data->name);
8248                else
8249                        pr_out_fmsg_end_object(dl);
8250                break;
8251        case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
8252                break;
8253        case DEVLINK_ATTR_FMSG_ARR_NEST_START:
8254                if (start)
8255                        pr_out_fmsg_start_array(dl, &fmsg_data->name);
8256                else
8257                        pr_out_fmsg_end_array(dl);
8258                break;
8259        default:
8260                return -EINVAL;
8261        }
8262        return MNL_CB_OK;
8263}
8264
8265static int cmd_fmsg_object_cb(const struct nlmsghdr *nlh, void *data)
8266{
8267        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
8268        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
8269        struct fmsg_cb_data *fmsg_data = data;
8270        struct dl *dl = fmsg_data->dl;
8271        struct nlattr *nla_object;
8272        int attr_type;
8273        int err;
8274
8275        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
8276        if (!tb[DEVLINK_ATTR_FMSG])
8277                return MNL_CB_ERROR;
8278
8279        mnl_attr_for_each_nested(nla_object, tb[DEVLINK_ATTR_FMSG]) {
8280                attr_type = mnl_attr_get_type(nla_object);
8281                switch (attr_type) {
8282                case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
8283                case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
8284                case DEVLINK_ATTR_FMSG_ARR_NEST_START:
8285                        err = cmd_fmsg_nest(fmsg_data, attr_type, true);
8286                        if (err != MNL_CB_OK)
8287                                return err;
8288                        break;
8289                case DEVLINK_ATTR_FMSG_NEST_END:
8290                        err = cmd_fmsg_nest(fmsg_data, attr_type, false);
8291                        if (err != MNL_CB_OK)
8292                                return err;
8293                        break;
8294                case DEVLINK_ATTR_FMSG_OBJ_NAME:
8295                        free(fmsg_data->name);
8296                        fmsg_data->name = strdup(mnl_attr_get_str(nla_object));
8297                        if (!fmsg_data->name)
8298                                return -ENOMEM;
8299                        break;
8300                case DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE:
8301                        fmsg_data->value_type = mnl_attr_get_u8(nla_object);
8302                        break;
8303                case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA:
8304                        pr_out_fmsg_name(dl, &fmsg_data->name);
8305                        err = fmsg_value_show(dl, fmsg_data->value_type,
8306                                              nla_object);
8307                        if (err != MNL_CB_OK)
8308                                return err;
8309                        break;
8310                default:
8311                        return -EINVAL;
8312                }
8313        }
8314        return MNL_CB_OK;
8315}
8316
8317static void cmd_fmsg_init(struct dl *dl, struct fmsg_cb_data *data)
8318{
8319        /* FMSG is dynamic: opening of an object or array causes a
8320         * newline. JSON starts with an { or [, but plain text should
8321         * not start with a new line. Ensure this by setting
8322         * g_new_line_count to 1: avoiding newline before the first
8323         * print.
8324         */
8325        g_new_line_count = 1;
8326        data->name = NULL;
8327        data->dl = dl;
8328        INIT_LIST_HEAD(&data->entry_list);
8329}
8330
8331static int cmd_health_object_common(struct dl *dl, uint8_t cmd, uint16_t flags)
8332{
8333        struct fmsg_cb_data data;
8334        struct nlmsghdr *nlh;
8335        int err;
8336
8337        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, cmd, flags | NLM_F_REQUEST | NLM_F_ACK);
8338
8339        err = dl_argv_parse_put(nlh, dl,
8340                                DL_OPT_HANDLE | DL_OPT_HANDLEP |
8341                                DL_OPT_HEALTH_REPORTER_NAME, 0);
8342        if (err)
8343                return err;
8344
8345        cmd_fmsg_init(dl, &data);
8346        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_fmsg_object_cb, &data);
8347        free(data.name);
8348        return err;
8349}
8350
8351static int cmd_health_dump_show(struct dl *dl)
8352{
8353        return cmd_health_object_common(dl,
8354                                        DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,
8355                                        NLM_F_DUMP);
8356}
8357
8358static int cmd_health_diagnose(struct dl *dl)
8359{
8360        return cmd_health_object_common(dl,
8361                                        DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE,
8362                                        0);
8363}
8364
8365static int cmd_health_test(struct dl *dl)
8366{
8367        return cmd_health_object_common(dl,
8368                                        DEVLINK_CMD_HEALTH_REPORTER_TEST,
8369                                        0);
8370}
8371
8372static int cmd_health_recover(struct dl *dl)
8373{
8374        struct nlmsghdr *nlh;
8375        int err;
8376
8377        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_RECOVER,
8378                               NLM_F_REQUEST | NLM_F_ACK);
8379
8380        err = dl_argv_parse_put(nlh, dl,
8381                                DL_OPT_HANDLE | DL_OPT_HANDLEP |
8382                                DL_OPT_HEALTH_REPORTER_NAME, 0);
8383        if (err)
8384                return err;
8385
8386        dl_opts_put(nlh, dl);
8387        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
8388}
8389
8390enum devlink_health_reporter_state {
8391        DEVLINK_HEALTH_REPORTER_STATE_HEALTHY,
8392        DEVLINK_HEALTH_REPORTER_STATE_ERROR,
8393};
8394
8395static const char *health_state_name(uint8_t state)
8396{
8397        switch (state) {
8398        case DEVLINK_HEALTH_REPORTER_STATE_HEALTHY:
8399                return HEALTH_REPORTER_STATE_HEALTHY_STR;
8400        case DEVLINK_HEALTH_REPORTER_STATE_ERROR:
8401                return HEALTH_REPORTER_STATE_ERROR_STR;
8402        default:
8403                return "<unknown state>";
8404        }
8405}
8406
8407static void pr_out_dump_reporter_format_logtime(struct dl *dl, const struct nlattr *attr)
8408{
8409        char dump_date[HEALTH_REPORTER_TIMESTAMP_FMT_LEN];
8410        char dump_time[HEALTH_REPORTER_TIMESTAMP_FMT_LEN];
8411        uint64_t time_ms = mnl_attr_get_u64(attr);
8412        struct sysinfo s_info;
8413        struct tm *info;
8414        time_t now, sec;
8415        int err;
8416
8417        time(&now);
8418        info = localtime(&now);
8419        err = sysinfo(&s_info);
8420        if (err)
8421                goto out;
8422        /* Subtract uptime in sec from now yields the time of system
8423         * uptime. To this, add time_ms which is the amount of
8424         * milliseconds elapsed between uptime and the dump taken.
8425         */
8426        sec = now - s_info.uptime + time_ms / 1000;
8427        info = localtime(&sec);
8428out:
8429        strftime(dump_date, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%Y-%m-%d", info);
8430        strftime(dump_time, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%H:%M:%S", info);
8431        check_indent_newline(dl);
8432        print_string(PRINT_ANY, "last_dump_date", "last_dump_date %s", dump_date);
8433        print_string(PRINT_ANY, "last_dump_time", " last_dump_time %s", dump_time);
8434}
8435
8436static void pr_out_dump_report_timestamp(struct dl *dl, const struct nlattr *attr)
8437{
8438        char dump_date[HEALTH_REPORTER_TIMESTAMP_FMT_LEN];
8439        char dump_time[HEALTH_REPORTER_TIMESTAMP_FMT_LEN];
8440        time_t tv_sec;
8441        struct tm *tm;
8442        uint64_t ts;
8443
8444        ts = mnl_attr_get_u64(attr);
8445        tv_sec = ts / 1000000000;
8446        tm = localtime(&tv_sec);
8447
8448        strftime(dump_date, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%Y-%m-%d", tm);
8449        strftime(dump_time, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%H:%M:%S", tm);
8450
8451        check_indent_newline(dl);
8452        print_string(PRINT_ANY, "last_dump_date", "last_dump_date %s", dump_date);
8453        print_string(PRINT_ANY, "last_dump_time", " last_dump_time %s", dump_time);
8454}
8455
8456static void pr_out_health(struct dl *dl, struct nlattr **tb_health,
8457                          bool print_device, bool print_port)
8458{
8459        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
8460        enum devlink_health_reporter_state state;
8461        int err;
8462
8463        err = mnl_attr_parse_nested(tb_health[DEVLINK_ATTR_HEALTH_REPORTER],
8464                                    attr_cb, tb);
8465        if (err != MNL_CB_OK)
8466                return;
8467
8468        if (!tb[DEVLINK_ATTR_HEALTH_REPORTER_NAME] ||
8469            !tb[DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT] ||
8470            !tb[DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT] ||
8471            !tb[DEVLINK_ATTR_HEALTH_REPORTER_STATE])
8472                return;
8473
8474        if (!print_device && !print_port)
8475                return;
8476        if (print_port) {
8477                if (!print_device && !tb_health[DEVLINK_ATTR_PORT_INDEX])
8478                        return;
8479                else if (tb_health[DEVLINK_ATTR_PORT_INDEX])
8480                        pr_out_port_handle_start_arr(dl, tb_health, false);
8481        }
8482        if (print_device) {
8483                if (!print_port && tb_health[DEVLINK_ATTR_PORT_INDEX])
8484                        return;
8485                else if (!tb_health[DEVLINK_ATTR_PORT_INDEX])
8486                        pr_out_handle_start_arr(dl, tb_health);
8487        }
8488
8489        check_indent_newline(dl);
8490        print_string(PRINT_ANY, "reporter", "reporter %s",
8491                     mnl_attr_get_str(tb[DEVLINK_ATTR_HEALTH_REPORTER_NAME]));
8492        if (!dl->json_output) {
8493                __pr_out_newline();
8494                __pr_out_indent_inc();
8495        }
8496        state = mnl_attr_get_u8(tb[DEVLINK_ATTR_HEALTH_REPORTER_STATE]);
8497        check_indent_newline(dl);
8498        print_string(PRINT_ANY, "state", "state %s", health_state_name(state));
8499        pr_out_u64(dl, "error",
8500                   mnl_attr_get_u64(tb[DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT]));
8501        pr_out_u64(dl, "recover",
8502                   mnl_attr_get_u64(tb[DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT]));
8503        if (tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS])
8504                pr_out_dump_report_timestamp(dl, tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS]);
8505        else if (tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS])
8506                pr_out_dump_reporter_format_logtime(dl, tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS]);
8507        if (tb[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD])
8508                pr_out_u64(dl, "grace_period",
8509                           mnl_attr_get_u64(tb[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]));
8510        if (tb[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])
8511                print_bool(PRINT_ANY, "auto_recover", " auto_recover %s",
8512                           mnl_attr_get_u8(tb[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]));
8513        if (tb[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP])
8514                print_bool(PRINT_ANY, "auto_dump", " auto_dump %s",
8515                           mnl_attr_get_u8(tb[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]));
8516
8517        __pr_out_indent_dec();
8518        pr_out_handle_end(dl);
8519}
8520
8521struct health_ctx {
8522        struct dl *dl;
8523        bool show_device;
8524        bool show_port;
8525};
8526
8527static int cmd_health_show_cb(const struct nlmsghdr *nlh, void *data)
8528{
8529        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
8530        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
8531        struct health_ctx *ctx = data;
8532        struct dl *dl = ctx->dl;
8533
8534        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
8535        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
8536            !tb[DEVLINK_ATTR_HEALTH_REPORTER])
8537                return MNL_CB_ERROR;
8538
8539        pr_out_health(dl, tb, ctx->show_device, ctx->show_port);
8540
8541        return MNL_CB_OK;
8542}
8543
8544static int __cmd_health_show(struct dl *dl, bool show_device, bool show_port)
8545{
8546        struct nlmsghdr *nlh;
8547        struct health_ctx ctx = { dl, show_device, show_port };
8548        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
8549        int err;
8550
8551        if (dl_argc(dl) == 0)
8552                flags |= NLM_F_DUMP;
8553        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_GET,
8554                               flags);
8555
8556        if (dl_argc(dl) > 0) {
8557                ctx.show_port = true;
8558                err = dl_argv_parse_put(nlh, dl,
8559                                        DL_OPT_HANDLE | DL_OPT_HANDLEP |
8560                                        DL_OPT_HEALTH_REPORTER_NAME, 0);
8561                if (err)
8562                        return err;
8563        }
8564        pr_out_section_start(dl, "health");
8565
8566        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_health_show_cb, &ctx);
8567        pr_out_section_end(dl);
8568        return err;
8569}
8570
8571static void cmd_health_help(void)
8572{
8573        pr_err("Usage: devlink health show [ { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME ]\n");
8574        pr_err("       devlink health recover { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME\n");
8575        pr_err("       devlink health diagnose { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME\n");
8576        pr_err("       devlink health test { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME\n");
8577        pr_err("       devlink health dump show { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME\n");
8578        pr_err("       devlink health dump clear { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME\n");
8579        pr_err("       devlink health set { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME\n");
8580        pr_err("                          [ grace_period MSEC ]\n");
8581        pr_err("                          [ auto_recover { true | false } ]\n");
8582        pr_err("                          [ auto_dump    { true | false } ]\n");
8583}
8584
8585static int cmd_health(struct dl *dl)
8586{
8587        if (dl_argv_match(dl, "help")) {
8588                cmd_health_help();
8589                return 0;
8590        } else if (dl_argv_match(dl, "show") ||
8591                   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
8592                dl_arg_inc(dl);
8593                return __cmd_health_show(dl, true, true);
8594        } else if (dl_argv_match(dl, "recover")) {
8595                dl_arg_inc(dl);
8596                return cmd_health_recover(dl);
8597        } else if (dl_argv_match(dl, "diagnose")) {
8598                dl_arg_inc(dl);
8599                return cmd_health_diagnose(dl);
8600        } else if (dl_argv_match(dl, "test")) {
8601                dl_arg_inc(dl);
8602                return cmd_health_test(dl);
8603        } else if (dl_argv_match(dl, "dump")) {
8604                dl_arg_inc(dl);
8605                if (dl_argv_match(dl, "show")) {
8606                        dl_arg_inc(dl);
8607                        return cmd_health_dump_show(dl);
8608                } else if (dl_argv_match(dl, "clear")) {
8609                        dl_arg_inc(dl);
8610                        return cmd_health_dump_clear(dl);
8611                }
8612        } else if (dl_argv_match(dl, "set")) {
8613                dl_arg_inc(dl);
8614                return cmd_health_set_params(dl);
8615        }
8616        pr_err("Command \"%s\" not found\n", dl_argv(dl));
8617        return -ENOENT;
8618}
8619
8620static const char *trap_type_name(uint8_t type)
8621{
8622        switch (type) {
8623        case DEVLINK_TRAP_TYPE_DROP:
8624                return "drop";
8625        case DEVLINK_TRAP_TYPE_EXCEPTION:
8626                return "exception";
8627        case DEVLINK_TRAP_TYPE_CONTROL:
8628                return "control";
8629        default:
8630                return "<unknown type>";
8631        }
8632}
8633
8634static const char *trap_action_name(uint8_t action)
8635{
8636        switch (action) {
8637        case DEVLINK_TRAP_ACTION_DROP:
8638                return "drop";
8639        case DEVLINK_TRAP_ACTION_TRAP:
8640                return "trap";
8641        case DEVLINK_TRAP_ACTION_MIRROR:
8642                return "mirror";
8643        default:
8644                return "<unknown action>";
8645        }
8646}
8647
8648static const char *trap_metadata_name(const struct nlattr *attr)
8649{
8650        switch (attr->nla_type) {
8651        case DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT:
8652                return "input_port";
8653        case DEVLINK_ATTR_TRAP_METADATA_TYPE_FA_COOKIE:
8654                return "flow_action_cookie";
8655        default:
8656                return "<unknown metadata type>";
8657        }
8658}
8659static void pr_out_trap_metadata(struct dl *dl, struct nlattr *attr)
8660{
8661        struct nlattr *attr_metadata;
8662
8663        pr_out_array_start(dl, "metadata");
8664        mnl_attr_for_each_nested(attr_metadata, attr) {
8665                check_indent_newline(dl);
8666                print_string(PRINT_ANY, NULL, "%s",
8667                             trap_metadata_name(attr_metadata));
8668        }
8669        pr_out_array_end(dl);
8670}
8671
8672static void pr_out_trap(struct dl *dl, struct nlattr **tb, bool array)
8673{
8674        uint8_t action = mnl_attr_get_u8(tb[DEVLINK_ATTR_TRAP_ACTION]);
8675        uint8_t type = mnl_attr_get_u8(tb[DEVLINK_ATTR_TRAP_TYPE]);
8676
8677        if (array)
8678                pr_out_handle_start_arr(dl, tb);
8679        else
8680                __pr_out_handle_start(dl, tb, true, false);
8681
8682        check_indent_newline(dl);
8683        print_string(PRINT_ANY, "name", "name %s",
8684                     mnl_attr_get_str(tb[DEVLINK_ATTR_TRAP_NAME]));
8685        print_string(PRINT_ANY, "type", " type %s", trap_type_name(type));
8686        print_bool(PRINT_ANY, "generic", " generic %s", !!tb[DEVLINK_ATTR_TRAP_GENERIC]);
8687        print_string(PRINT_ANY, "action", " action %s", trap_action_name(action));
8688        print_string(PRINT_ANY, "group", " group %s",
8689                     mnl_attr_get_str(tb[DEVLINK_ATTR_TRAP_GROUP_NAME]));
8690        if (dl->verbose)
8691                pr_out_trap_metadata(dl, tb[DEVLINK_ATTR_TRAP_METADATA]);
8692        pr_out_stats(dl, tb[DEVLINK_ATTR_STATS]);
8693        pr_out_handle_end(dl);
8694}
8695
8696static int cmd_trap_show_cb(const struct nlmsghdr *nlh, void *data)
8697{
8698        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
8699        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
8700        struct dl *dl = data;
8701
8702        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
8703        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
8704            !tb[DEVLINK_ATTR_TRAP_NAME] || !tb[DEVLINK_ATTR_TRAP_TYPE] ||
8705            !tb[DEVLINK_ATTR_TRAP_ACTION] ||
8706            !tb[DEVLINK_ATTR_TRAP_GROUP_NAME] ||
8707            !tb[DEVLINK_ATTR_TRAP_METADATA] || !tb[DEVLINK_ATTR_STATS])
8708                return MNL_CB_ERROR;
8709
8710        pr_out_trap(dl, tb, true);
8711
8712        return MNL_CB_OK;
8713}
8714
8715static void cmd_trap_help(void)
8716{
8717        pr_err("Usage: devlink trap set DEV trap TRAP [ action { trap | drop | mirror } ]\n");
8718        pr_err("       devlink trap show [ DEV trap TRAP ]\n");
8719        pr_err("       devlink trap group set DEV group GROUP [ action { trap | drop | mirror } ]\n");
8720        pr_err("                              [ policer POLICER ] [ nopolicer ]\n");
8721        pr_err("       devlink trap group show [ DEV group GROUP ]\n");
8722        pr_err("       devlink trap policer set DEV policer POLICER [ rate RATE ] [ burst BURST ]\n");
8723        pr_err("       devlink trap policer show DEV policer POLICER\n");
8724}
8725
8726static int cmd_trap_show(struct dl *dl)
8727{
8728        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
8729        struct nlmsghdr *nlh;
8730        int err;
8731
8732        if (dl_argc(dl) == 0)
8733                flags |= NLM_F_DUMP;
8734
8735        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_TRAP_GET, flags);
8736
8737        if (dl_argc(dl) > 0) {
8738                err = dl_argv_parse_put(nlh, dl,
8739                                        DL_OPT_HANDLE | DL_OPT_TRAP_NAME, 0);
8740                if (err)
8741                        return err;
8742        }
8743
8744        pr_out_section_start(dl, "trap");
8745        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_trap_show_cb, dl);
8746        pr_out_section_end(dl);
8747
8748        return err;
8749}
8750
8751static int cmd_trap_set(struct dl *dl)
8752{
8753        struct nlmsghdr *nlh;
8754        int err;
8755
8756        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_TRAP_SET,
8757                               NLM_F_REQUEST | NLM_F_ACK);
8758
8759        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_TRAP_NAME,
8760                                DL_OPT_TRAP_ACTION);
8761        if (err)
8762                return err;
8763
8764        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
8765}
8766
8767static void pr_out_trap_group(struct dl *dl, struct nlattr **tb, bool array)
8768{
8769        if (array)
8770                pr_out_handle_start_arr(dl, tb);
8771        else
8772                __pr_out_handle_start(dl, tb, true, false);
8773
8774        check_indent_newline(dl);
8775        print_string(PRINT_ANY, "name", "name %s",
8776                     mnl_attr_get_str(tb[DEVLINK_ATTR_TRAP_GROUP_NAME]));
8777        print_bool(PRINT_ANY, "generic", " generic %s", !!tb[DEVLINK_ATTR_TRAP_GENERIC]);
8778        if (tb[DEVLINK_ATTR_TRAP_POLICER_ID])
8779                print_uint(PRINT_ANY, "policer", " policer %u",
8780                           mnl_attr_get_u32(tb[DEVLINK_ATTR_TRAP_POLICER_ID]));
8781        pr_out_stats(dl, tb[DEVLINK_ATTR_STATS]);
8782        pr_out_handle_end(dl);
8783}
8784
8785static int cmd_trap_group_show_cb(const struct nlmsghdr *nlh, void *data)
8786{
8787        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
8788        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
8789        struct dl *dl = data;
8790
8791        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
8792        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
8793            !tb[DEVLINK_ATTR_TRAP_GROUP_NAME] || !tb[DEVLINK_ATTR_STATS])
8794                return MNL_CB_ERROR;
8795
8796        pr_out_trap_group(dl, tb, true);
8797
8798        return MNL_CB_OK;
8799}
8800
8801static int cmd_trap_group_show(struct dl *dl)
8802{
8803        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
8804        struct nlmsghdr *nlh;
8805        int err;
8806
8807        if (dl_argc(dl) == 0)
8808                flags |= NLM_F_DUMP;
8809
8810        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_TRAP_GROUP_GET, flags);
8811
8812        if (dl_argc(dl) > 0) {
8813                err = dl_argv_parse_put(nlh, dl,
8814                                        DL_OPT_HANDLE | DL_OPT_TRAP_GROUP_NAME,
8815                                        0);
8816                if (err)
8817                        return err;
8818        }
8819
8820        pr_out_section_start(dl, "trap_group");
8821        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_trap_group_show_cb, dl);
8822        pr_out_section_end(dl);
8823
8824        return err;
8825}
8826
8827static int cmd_trap_group_set(struct dl *dl)
8828{
8829        struct nlmsghdr *nlh;
8830        int err;
8831
8832        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_TRAP_GROUP_SET,
8833                               NLM_F_REQUEST | NLM_F_ACK);
8834
8835        err = dl_argv_parse_put(nlh, dl,
8836                                DL_OPT_HANDLE | DL_OPT_TRAP_GROUP_NAME,
8837                                DL_OPT_TRAP_ACTION | DL_OPT_TRAP_POLICER_ID);
8838        if (err)
8839                return err;
8840
8841        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
8842}
8843
8844static int cmd_trap_group(struct dl *dl)
8845{
8846        if (dl_argv_match(dl, "help")) {
8847                cmd_trap_help();
8848                return 0;
8849        } else if (dl_argv_match(dl, "show") ||
8850                   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
8851                dl_arg_inc(dl);
8852                return cmd_trap_group_show(dl);
8853        } else if (dl_argv_match(dl, "set")) {
8854                dl_arg_inc(dl);
8855                return cmd_trap_group_set(dl);
8856        }
8857        pr_err("Command \"%s\" not found\n", dl_argv(dl));
8858        return -ENOENT;
8859}
8860
8861static void pr_out_trap_policer(struct dl *dl, struct nlattr **tb, bool array)
8862{
8863        if (array)
8864                pr_out_handle_start_arr(dl, tb);
8865        else
8866                __pr_out_handle_start(dl, tb, true, false);
8867
8868        check_indent_newline(dl);
8869        print_uint(PRINT_ANY, "policer", "policer %u",
8870                   mnl_attr_get_u32(tb[DEVLINK_ATTR_TRAP_POLICER_ID]));
8871        print_u64(PRINT_ANY, "rate", " rate %llu",
8872                   mnl_attr_get_u64(tb[DEVLINK_ATTR_TRAP_POLICER_RATE]));
8873        print_u64(PRINT_ANY, "burst", " burst %llu",
8874                   mnl_attr_get_u64(tb[DEVLINK_ATTR_TRAP_POLICER_BURST]));
8875        if (tb[DEVLINK_ATTR_STATS])
8876                pr_out_stats(dl, tb[DEVLINK_ATTR_STATS]);
8877        pr_out_handle_end(dl);
8878}
8879
8880static int cmd_trap_policer_show_cb(const struct nlmsghdr *nlh, void *data)
8881{
8882        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
8883        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
8884        struct dl *dl = data;
8885
8886        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
8887        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
8888            !tb[DEVLINK_ATTR_TRAP_POLICER_ID] ||
8889            !tb[DEVLINK_ATTR_TRAP_POLICER_RATE] ||
8890            !tb[DEVLINK_ATTR_TRAP_POLICER_BURST])
8891                return MNL_CB_ERROR;
8892
8893        pr_out_trap_policer(dl, tb, true);
8894
8895        return MNL_CB_OK;
8896}
8897
8898static int cmd_trap_policer_show(struct dl *dl)
8899{
8900        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
8901        struct nlmsghdr *nlh;
8902        int err;
8903
8904        if (dl_argc(dl) == 0)
8905                flags |= NLM_F_DUMP;
8906
8907        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_TRAP_POLICER_GET, flags);
8908
8909        if (dl_argc(dl) > 0) {
8910                err = dl_argv_parse_put(nlh, dl,
8911                                        DL_OPT_HANDLE | DL_OPT_TRAP_POLICER_ID,
8912                                        0);
8913                if (err)
8914                        return err;
8915        }
8916
8917        pr_out_section_start(dl, "trap_policer");
8918        err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_trap_policer_show_cb, dl);
8919        pr_out_section_end(dl);
8920
8921        return err;
8922}
8923
8924static int cmd_trap_policer_set(struct dl *dl)
8925{
8926        struct nlmsghdr *nlh;
8927        int err;
8928
8929        nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_TRAP_POLICER_SET,
8930                               NLM_F_REQUEST | NLM_F_ACK);
8931
8932        err = dl_argv_parse_put(nlh, dl,
8933                                DL_OPT_HANDLE | DL_OPT_TRAP_POLICER_ID,
8934                                DL_OPT_TRAP_POLICER_RATE |
8935                                DL_OPT_TRAP_POLICER_BURST);
8936        if (err)
8937                return err;
8938
8939        return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
8940}
8941
8942static int cmd_trap_policer(struct dl *dl)
8943{
8944        if (dl_argv_match(dl, "help")) {
8945                cmd_trap_help();
8946                return 0;
8947        } else if (dl_argv_match(dl, "show") ||
8948                   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
8949                dl_arg_inc(dl);
8950                return cmd_trap_policer_show(dl);
8951        } else if (dl_argv_match(dl, "set")) {
8952                dl_arg_inc(dl);
8953                return cmd_trap_policer_set(dl);
8954        }
8955        pr_err("Command \"%s\" not found\n", dl_argv(dl));
8956        return -ENOENT;
8957}
8958
8959static int cmd_trap(struct dl *dl)
8960{
8961        if (dl_argv_match(dl, "help")) {
8962                cmd_trap_help();
8963                return 0;
8964        } else if (dl_argv_match(dl, "show") ||
8965                   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
8966                dl_arg_inc(dl);
8967                return cmd_trap_show(dl);
8968        } else if (dl_argv_match(dl, "set")) {
8969                dl_arg_inc(dl);
8970                return cmd_trap_set(dl);
8971        } else if (dl_argv_match(dl, "group")) {
8972                dl_arg_inc(dl);
8973                return cmd_trap_group(dl);
8974        } else if (dl_argv_match(dl, "policer")) {
8975                dl_arg_inc(dl);
8976                return cmd_trap_policer(dl);
8977        }
8978        pr_err("Command \"%s\" not found\n", dl_argv(dl));
8979        return -ENOENT;
8980}
8981
8982static void help(void)
8983{
8984        pr_err("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n"
8985               "       devlink [ -f[orce] ] -b[atch] filename -N[etns] netnsname\n"
8986               "where  OBJECT := { dev | port | sb | monitor | dpipe | resource | region | health | trap }\n"
8987               "       OPTIONS := { -V[ersion] | -n[o-nice-names] | -j[son] | -p[retty] | -v[erbose] -s[tatistics] }\n");
8988}
8989
8990static int dl_cmd(struct dl *dl, int argc, char **argv)
8991{
8992        dl->argc = argc;
8993        dl->argv = argv;
8994
8995        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
8996                help();
8997                return 0;
8998        } else if (dl_argv_match(dl, "dev")) {
8999                dl_arg_inc(dl);
9000                return cmd_dev(dl);
9001        } else if (dl_argv_match(dl, "port")) {
9002                dl_arg_inc(dl);
9003                return cmd_port(dl);
9004        } else if (dl_argv_match(dl, "sb")) {
9005                dl_arg_inc(dl);
9006                return cmd_sb(dl);
9007        } else if (dl_argv_match(dl, "monitor")) {
9008                dl_arg_inc(dl);
9009                return cmd_mon(dl);
9010        } else if (dl_argv_match(dl, "dpipe")) {
9011                dl_arg_inc(dl);
9012                return cmd_dpipe(dl);
9013        } else if (dl_argv_match(dl, "resource")) {
9014                dl_arg_inc(dl);
9015                return cmd_resource(dl);
9016        } else if (dl_argv_match(dl, "region")) {
9017                dl_arg_inc(dl);
9018                return cmd_region(dl);
9019        } else if (dl_argv_match(dl, "health")) {
9020                dl_arg_inc(dl);
9021                return cmd_health(dl);
9022        } else if (dl_argv_match(dl, "trap")) {
9023                dl_arg_inc(dl);
9024                return cmd_trap(dl);
9025        }
9026        pr_err("Object \"%s\" not found\n", dl_argv(dl));
9027        return -ENOENT;
9028}
9029
9030static int dl_init(struct dl *dl)
9031{
9032        int err;
9033
9034        err = mnlu_gen_socket_open(&dl->nlg, DEVLINK_GENL_NAME,
9035                                   DEVLINK_GENL_VERSION);
9036        if (err) {
9037                pr_err("Failed to connect to devlink Netlink\n");
9038                return -errno;
9039        }
9040
9041        err = ifname_map_init(dl);
9042        if (err) {
9043                pr_err("Failed to create index map\n");
9044                goto err_ifname_map_create;
9045        }
9046        new_json_obj_plain(dl->json_output);
9047        return 0;
9048
9049err_ifname_map_create:
9050        mnlu_gen_socket_close(&dl->nlg);
9051        return err;
9052}
9053
9054static void dl_fini(struct dl *dl)
9055{
9056        delete_json_obj_plain();
9057        ifname_map_fini(dl);
9058        mnlu_gen_socket_close(&dl->nlg);
9059}
9060
9061static struct dl *dl_alloc(void)
9062{
9063        struct dl *dl;
9064
9065        dl = calloc(1, sizeof(*dl));
9066        if (!dl)
9067                return NULL;
9068        return dl;
9069}
9070
9071static void dl_free(struct dl *dl)
9072{
9073        free(dl);
9074}
9075
9076static int dl_batch_cmd(int argc, char *argv[], void *data)
9077{
9078        struct dl *dl = data;
9079
9080        return dl_cmd(dl, argc, argv);
9081}
9082
9083static int dl_batch(struct dl *dl, const char *name, bool force)
9084{
9085        return do_batch(name, force, dl_batch_cmd, dl);
9086}
9087
9088int main(int argc, char **argv)
9089{
9090        static const struct option long_options[] = {
9091                { "Version",            no_argument,            NULL, 'V' },
9092                { "force",              no_argument,            NULL, 'f' },
9093                { "batch",              required_argument,      NULL, 'b' },
9094                { "no-nice-names",      no_argument,            NULL, 'n' },
9095                { "json",               no_argument,            NULL, 'j' },
9096                { "pretty",             no_argument,            NULL, 'p' },
9097                { "verbose",            no_argument,            NULL, 'v' },
9098                { "statistics",         no_argument,            NULL, 's' },
9099                { "Netns",              required_argument,      NULL, 'N' },
9100                { "iec",                no_argument,            NULL, 'i' },
9101                { NULL, 0, NULL, 0 }
9102        };
9103        const char *batch_file = NULL;
9104        bool force = false;
9105        struct dl *dl;
9106        int opt;
9107        int err;
9108        int ret;
9109
9110        dl = dl_alloc();
9111        if (!dl) {
9112                pr_err("Failed to allocate memory for devlink\n");
9113                return EXIT_FAILURE;
9114        }
9115
9116        while ((opt = getopt_long(argc, argv, "Vfb:njpvsN:i",
9117                                  long_options, NULL)) >= 0) {
9118
9119                switch (opt) {
9120                case 'V':
9121                        printf("devlink utility, iproute2-%s\n", version);
9122                        ret = EXIT_SUCCESS;
9123                        goto dl_free;
9124                case 'f':
9125                        force = true;
9126                        break;
9127                case 'b':
9128                        batch_file = optarg;
9129                        break;
9130                case 'n':
9131                        dl->no_nice_names = true;
9132                        break;
9133                case 'j':
9134                        dl->json_output = true;
9135                        break;
9136                case 'p':
9137                        pretty = true;
9138                        break;
9139                case 'v':
9140                        dl->verbose = true;
9141                        break;
9142                case 's':
9143                        dl->stats = true;
9144                        break;
9145                case 'N':
9146                        if (netns_switch(optarg)) {
9147                                ret = EXIT_FAILURE;
9148                                goto dl_free;
9149                        }
9150                        break;
9151                case 'i':
9152                        use_iec = true;
9153                        break;
9154                default:
9155                        pr_err("Unknown option.\n");
9156                        help();
9157                        ret = EXIT_FAILURE;
9158                        goto dl_free;
9159                }
9160        }
9161
9162        argc -= optind;
9163        argv += optind;
9164
9165        err = dl_init(dl);
9166        if (err) {
9167                ret = EXIT_FAILURE;
9168                goto dl_free;
9169        }
9170
9171        if (batch_file)
9172                err = dl_batch(dl, batch_file, force);
9173        else
9174                err = dl_cmd(dl, argc, argv);
9175
9176        if (err) {
9177                ret = EXIT_FAILURE;
9178                goto dl_fini;
9179        }
9180
9181        ret = EXIT_SUCCESS;
9182
9183dl_fini:
9184        dl_fini(dl);
9185dl_free:
9186        dl_free(dl);
9187
9188        return ret;
9189}
9190