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 "json_print.h"
  43#include "utils.h"
  44#include "namespace.h"
  45
  46#define ESWITCH_MODE_LEGACY "legacy"
  47#define ESWITCH_MODE_SWITCHDEV "switchdev"
  48#define ESWITCH_INLINE_MODE_NONE "none"
  49#define ESWITCH_INLINE_MODE_LINK "link"
  50#define ESWITCH_INLINE_MODE_NETWORK "network"
  51#define ESWITCH_INLINE_MODE_TRANSPORT "transport"
  52
  53#define ESWITCH_ENCAP_MODE_NONE "none"
  54#define ESWITCH_ENCAP_MODE_BASIC "basic"
  55
  56#define PARAM_CMODE_RUNTIME_STR "runtime"
  57#define PARAM_CMODE_DRIVERINIT_STR "driverinit"
  58#define PARAM_CMODE_PERMANENT_STR "permanent"
  59#define DL_ARGS_REQUIRED_MAX_ERR_LEN 80
  60
  61#define HEALTH_REPORTER_STATE_HEALTHY_STR "healthy"
  62#define HEALTH_REPORTER_STATE_ERROR_STR "error"
  63#define HEALTH_REPORTER_TIMESTAMP_FMT_LEN 80
  64
  65static int g_new_line_count;
  66static int g_indent_level;
  67static bool g_indent_newline;
  68
  69#define INDENT_STR_STEP 2
  70#define INDENT_STR_MAXLEN 32
  71static char g_indent_str[INDENT_STR_MAXLEN + 1] = "";
  72
  73static void __attribute__((format(printf, 1, 2)))
  74pr_err(const char *fmt, ...)
  75{
  76        va_list ap;
  77
  78        va_start(ap, fmt);
  79        vfprintf(stderr, fmt, ap);
  80        va_end(ap);
  81}
  82
  83static void __attribute__((format(printf, 1, 2)))
  84pr_out(const char *fmt, ...)
  85{
  86        va_list ap;
  87
  88        if (g_indent_newline) {
  89                printf("%s", g_indent_str);
  90                g_indent_newline = false;
  91        }
  92        va_start(ap, fmt);
  93        vprintf(fmt, ap);
  94        va_end(ap);
  95        g_new_line_count = 0;
  96}
  97
  98static void __attribute__((format(printf, 2, 3)))
  99pr_out_sp(unsigned int num, const char *fmt, ...)
 100{
 101        va_list ap;
 102        int ret;
 103
 104        va_start(ap, fmt);
 105        ret = vprintf(fmt, ap);
 106        va_end(ap);
 107
 108        if (ret < num)
 109                printf("%*s", num - ret, "");
 110        g_new_line_count = 0;                   \
 111}
 112
 113static void __attribute__((format(printf, 1, 2)))
 114pr_out_tty(const char *fmt, ...)
 115{
 116        va_list ap;
 117
 118        if (!isatty(STDOUT_FILENO))
 119                return;
 120        va_start(ap, fmt);
 121        vprintf(fmt, ap);
 122        va_end(ap);
 123}
 124
 125static void __pr_out_indent_inc(void)
 126{
 127        if (g_indent_level + INDENT_STR_STEP > INDENT_STR_MAXLEN)
 128                return;
 129        g_indent_level += INDENT_STR_STEP;
 130        memset(g_indent_str, ' ', sizeof(g_indent_str));
 131        g_indent_str[g_indent_level] = '\0';
 132}
 133
 134static void __pr_out_indent_dec(void)
 135{
 136        if (g_indent_level - INDENT_STR_STEP < 0)
 137                return;
 138        g_indent_level -= INDENT_STR_STEP;
 139        g_indent_str[g_indent_level] = '\0';
 140}
 141
 142static void __pr_out_newline(void)
 143{
 144        if (g_new_line_count < 1) {
 145                pr_out("\n");
 146                g_indent_newline = true;
 147        }
 148        g_new_line_count++;
 149}
 150
 151static int _mnlg_socket_recv_run(struct mnlg_socket *nlg,
 152                                 mnl_cb_t data_cb, void *data)
 153{
 154        int err;
 155
 156        err = mnlg_socket_recv_run(nlg, data_cb, data);
 157        if (err < 0) {
 158                pr_err("devlink answers: %s\n", strerror(errno));
 159                return -errno;
 160        }
 161        return 0;
 162}
 163
 164static void dummy_signal_handler(int signum)
 165{
 166}
 167
 168static int _mnlg_socket_recv_run_intr(struct mnlg_socket *nlg,
 169                                      mnl_cb_t data_cb, void *data)
 170{
 171        struct sigaction act, oact;
 172        int err;
 173
 174        act.sa_handler = dummy_signal_handler;
 175        sigemptyset(&act.sa_mask);
 176        act.sa_flags = SA_NODEFER;
 177
 178        sigaction(SIGINT, &act, &oact);
 179        err = mnlg_socket_recv_run(nlg, data_cb, data);
 180        sigaction(SIGINT, &oact, NULL);
 181        if (err < 0 && errno != EINTR) {
 182                pr_err("devlink answers: %s\n", strerror(errno));
 183                return -errno;
 184        }
 185        return 0;
 186}
 187
 188static int _mnlg_socket_send(struct mnlg_socket *nlg,
 189                             const struct nlmsghdr *nlh)
 190{
 191        int err;
 192
 193        err = mnlg_socket_send(nlg, nlh);
 194        if (err < 0) {
 195                pr_err("Failed to call mnlg_socket_send\n");
 196                return -errno;
 197        }
 198        return 0;
 199}
 200
 201static int _mnlg_socket_sndrcv(struct mnlg_socket *nlg,
 202                               const struct nlmsghdr *nlh,
 203                               mnl_cb_t data_cb, void *data)
 204{
 205        int err;
 206
 207        err = _mnlg_socket_send(nlg, nlh);
 208        if (err)
 209                return err;
 210        return _mnlg_socket_recv_run(nlg, data_cb, data);
 211}
 212
 213static int _mnlg_socket_group_add(struct mnlg_socket *nlg,
 214                                  const char *group_name)
 215{
 216        int err;
 217
 218        err = mnlg_socket_group_add(nlg, group_name);
 219        if (err < 0) {
 220                pr_err("Failed to call mnlg_socket_group_add\n");
 221                return -errno;
 222        }
 223        return 0;
 224}
 225
 226struct ifname_map {
 227        struct list_head list;
 228        char *bus_name;
 229        char *dev_name;
 230        uint32_t port_index;
 231        char *ifname;
 232};
 233
 234static struct ifname_map *ifname_map_alloc(const char *bus_name,
 235                                           const char *dev_name,
 236                                           uint32_t port_index,
 237                                           const char *ifname)
 238{
 239        struct ifname_map *ifname_map;
 240
 241        ifname_map = calloc(1, sizeof(*ifname_map));
 242        if (!ifname_map)
 243                return NULL;
 244        ifname_map->bus_name = strdup(bus_name);
 245        ifname_map->dev_name = strdup(dev_name);
 246        ifname_map->port_index = port_index;
 247        ifname_map->ifname = strdup(ifname);
 248        if (!ifname_map->bus_name || !ifname_map->dev_name ||
 249            !ifname_map->ifname) {
 250                free(ifname_map->ifname);
 251                free(ifname_map->dev_name);
 252                free(ifname_map->bus_name);
 253                free(ifname_map);
 254                return NULL;
 255        }
 256        return ifname_map;
 257}
 258
 259static void ifname_map_free(struct ifname_map *ifname_map)
 260{
 261        free(ifname_map->ifname);
 262        free(ifname_map->dev_name);
 263        free(ifname_map->bus_name);
 264        free(ifname_map);
 265}
 266
 267#define DL_OPT_HANDLE           BIT(0)
 268#define DL_OPT_HANDLEP          BIT(1)
 269#define DL_OPT_PORT_TYPE        BIT(2)
 270#define DL_OPT_PORT_COUNT       BIT(3)
 271#define DL_OPT_SB               BIT(4)
 272#define DL_OPT_SB_POOL          BIT(5)
 273#define DL_OPT_SB_SIZE          BIT(6)
 274#define DL_OPT_SB_TYPE          BIT(7)
 275#define DL_OPT_SB_THTYPE        BIT(8)
 276#define DL_OPT_SB_TH            BIT(9)
 277#define DL_OPT_SB_TC            BIT(10)
 278#define DL_OPT_ESWITCH_MODE     BIT(11)
 279#define DL_OPT_ESWITCH_INLINE_MODE      BIT(12)
 280#define DL_OPT_DPIPE_TABLE_NAME BIT(13)
 281#define DL_OPT_DPIPE_TABLE_COUNTERS     BIT(14)
 282#define DL_OPT_ESWITCH_ENCAP_MODE       BIT(15)
 283#define DL_OPT_RESOURCE_PATH    BIT(16)
 284#define DL_OPT_RESOURCE_SIZE    BIT(17)
 285#define DL_OPT_PARAM_NAME       BIT(18)
 286#define DL_OPT_PARAM_VALUE      BIT(19)
 287#define DL_OPT_PARAM_CMODE      BIT(20)
 288#define DL_OPT_HANDLE_REGION            BIT(21)
 289#define DL_OPT_REGION_SNAPSHOT_ID       BIT(22)
 290#define DL_OPT_REGION_ADDRESS           BIT(23)
 291#define DL_OPT_REGION_LENGTH            BIT(24)
 292#define DL_OPT_FLASH_FILE_NAME  BIT(25)
 293#define DL_OPT_FLASH_COMPONENT  BIT(26)
 294#define DL_OPT_HEALTH_REPORTER_NAME     BIT(27)
 295#define DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD  BIT(28)
 296#define DL_OPT_HEALTH_REPORTER_AUTO_RECOVER     BIT(29)
 297#define DL_OPT_TRAP_NAME                BIT(30)
 298#define DL_OPT_TRAP_ACTION              BIT(31)
 299#define DL_OPT_TRAP_GROUP_NAME          BIT(32)
 300#define DL_OPT_NETNS    BIT(33)
 301#define DL_OPT_TRAP_POLICER_ID          BIT(34)
 302#define DL_OPT_TRAP_POLICER_RATE        BIT(35)
 303#define DL_OPT_TRAP_POLICER_BURST       BIT(36)
 304#define DL_OPT_HEALTH_REPORTER_AUTO_DUMP     BIT(37)
 305#define DL_OPT_PORT_FUNCTION_HW_ADDR BIT(38)
 306#define DL_OPT_FLASH_OVERWRITE          BIT(39)
 307#define DL_OPT_RELOAD_ACTION            BIT(40)
 308#define DL_OPT_RELOAD_LIMIT     BIT(41)
 309
 310struct dl_opts {
 311        uint64_t present; /* flags of present items */
 312        char *bus_name;
 313        char *dev_name;
 314        uint32_t port_index;
 315        enum devlink_port_type port_type;
 316        uint32_t port_count;
 317        uint32_t sb_index;
 318        uint16_t sb_pool_index;
 319        uint32_t sb_pool_size;
 320        enum devlink_sb_pool_type sb_pool_type;
 321        enum devlink_sb_threshold_type sb_pool_thtype;
 322        uint32_t sb_threshold;
 323        uint16_t sb_tc_index;
 324        enum devlink_eswitch_mode eswitch_mode;
 325        enum devlink_eswitch_inline_mode eswitch_inline_mode;
 326        const char *dpipe_table_name;
 327        bool dpipe_counters_enabled;
 328        enum devlink_eswitch_encap_mode eswitch_encap_mode;
 329        const char *resource_path;
 330        uint64_t resource_size;
 331        uint32_t resource_id;
 332        bool resource_id_valid;
 333        const char *param_name;
 334        const char *param_value;
 335        enum devlink_param_cmode cmode;
 336        char *region_name;
 337        uint32_t region_snapshot_id;
 338        uint64_t region_address;
 339        uint64_t region_length;
 340        const char *flash_file_name;
 341        const char *flash_component;
 342        const char *reporter_name;
 343        uint64_t reporter_graceful_period;
 344        bool reporter_auto_recover;
 345        bool reporter_auto_dump;
 346        const char *trap_name;
 347        const char *trap_group_name;
 348        enum devlink_trap_action trap_action;
 349        bool netns_is_pid;
 350        uint32_t netns;
 351        uint32_t trap_policer_id;
 352        uint64_t trap_policer_rate;
 353        uint64_t trap_policer_burst;
 354        char port_function_hw_addr[MAX_ADDR_LEN];
 355        uint32_t port_function_hw_addr_len;
 356        uint32_t overwrite_mask;
 357        enum devlink_reload_action reload_action;
 358        enum devlink_reload_limit reload_limit;
 359};
 360
 361struct dl {
 362        struct mnlg_socket *nlg;
 363        struct list_head ifname_map_list;
 364        int argc;
 365        char **argv;
 366        bool no_nice_names;
 367        struct dl_opts opts;
 368        bool json_output;
 369        bool pretty_output;
 370        bool verbose;
 371        bool stats;
 372        struct {
 373                bool present;
 374                char *bus_name;
 375                char *dev_name;
 376                uint32_t port_index;
 377        } arr_last;
 378};
 379
 380static int dl_argc(struct dl *dl)
 381{
 382        return dl->argc;
 383}
 384
 385static char *dl_argv(struct dl *dl)
 386{
 387        if (dl_argc(dl) == 0)
 388                return NULL;
 389        return *dl->argv;
 390}
 391
 392static void dl_arg_inc(struct dl *dl)
 393{
 394        if (dl_argc(dl) == 0)
 395                return;
 396        dl->argc--;
 397        dl->argv++;
 398}
 399
 400static void dl_arg_dec(struct dl *dl)
 401{
 402        dl->argc++;
 403        dl->argv--;
 404}
 405
 406static char *dl_argv_next(struct dl *dl)
 407{
 408        char *ret;
 409
 410        if (dl_argc(dl) == 0)
 411                return NULL;
 412
 413        ret = *dl->argv;
 414        dl_arg_inc(dl);
 415        return ret;
 416}
 417
 418static char *dl_argv_index(struct dl *dl, unsigned int index)
 419{
 420        if (index >= dl_argc(dl))
 421                return NULL;
 422        return dl->argv[index];
 423}
 424
 425static int strcmpx(const char *str1, const char *str2)
 426{
 427        if (strlen(str1) > strlen(str2))
 428                return -1;
 429        return strncmp(str1, str2, strlen(str1));
 430}
 431
 432static bool dl_argv_match(struct dl *dl, const char *pattern)
 433{
 434        if (dl_argc(dl) == 0)
 435                return false;
 436        return strcmpx(dl_argv(dl), pattern) == 0;
 437}
 438
 439static bool dl_no_arg(struct dl *dl)
 440{
 441        return dl_argc(dl) == 0;
 442}
 443
 444static void __pr_out_indent_newline(struct dl *dl)
 445{
 446        if (!g_indent_newline && !dl->json_output)
 447                pr_out(" ");
 448}
 449
 450static bool is_binary_eol(int i)
 451{
 452        return !(i%16);
 453}
 454
 455static void pr_out_binary_value(struct dl *dl, uint8_t *data, uint32_t len)
 456{
 457        int i = 0;
 458
 459        while (i < len) {
 460                if (dl->json_output)
 461                        print_int(PRINT_JSON, NULL, NULL, data[i]);
 462                else
 463                        pr_out("%02x ", data[i]);
 464                i++;
 465                if (!dl->json_output && is_binary_eol(i))
 466                        __pr_out_newline();
 467        }
 468        if (!dl->json_output && !is_binary_eol(i))
 469                __pr_out_newline();
 470}
 471
 472static void pr_out_name(struct dl *dl, const char *name)
 473{
 474        __pr_out_indent_newline(dl);
 475        if (dl->json_output)
 476                print_string(PRINT_JSON, name, NULL, NULL);
 477        else
 478                pr_out("%s:", name);
 479}
 480
 481static void pr_out_u64(struct dl *dl, const char *name, uint64_t val)
 482{
 483        __pr_out_indent_newline(dl);
 484        if (val == (uint64_t) -1)
 485                return print_string_name_value(name, "unlimited");
 486
 487        if (dl->json_output)
 488                print_u64(PRINT_JSON, name, NULL, val);
 489        else
 490                pr_out("%s %"PRIu64, name, val);
 491}
 492
 493static void pr_out_section_start(struct dl *dl, const char *name)
 494{
 495        if (dl->json_output) {
 496                open_json_object(NULL);
 497                open_json_object(name);
 498        }
 499}
 500
 501static void pr_out_section_end(struct dl *dl)
 502{
 503        if (dl->json_output) {
 504                if (dl->arr_last.present)
 505                        close_json_array(PRINT_JSON, NULL);
 506                close_json_object();
 507                close_json_object();
 508        }
 509}
 510
 511static void pr_out_array_start(struct dl *dl, const char *name)
 512{
 513        if (dl->json_output) {
 514                open_json_array(PRINT_JSON, name);
 515        } else {
 516                __pr_out_indent_inc();
 517                __pr_out_newline();
 518                pr_out("%s:", name);
 519                __pr_out_indent_inc();
 520                __pr_out_newline();
 521        }
 522}
 523
 524static void pr_out_array_end(struct dl *dl)
 525{
 526        if (dl->json_output) {
 527                close_json_array(PRINT_JSON, NULL);
 528        } else {
 529                __pr_out_indent_dec();
 530                __pr_out_indent_dec();
 531        }
 532}
 533
 534static void pr_out_object_start(struct dl *dl, const char *name)
 535{
 536        if (dl->json_output) {
 537                open_json_object(name);
 538        } else {
 539                __pr_out_indent_inc();
 540                __pr_out_newline();
 541                pr_out("%s:", name);
 542                __pr_out_indent_inc();
 543                __pr_out_newline();
 544        }
 545}
 546
 547static void pr_out_object_end(struct dl *dl)
 548{
 549        if (dl->json_output) {
 550                close_json_object();
 551        } else {
 552                __pr_out_indent_dec();
 553                __pr_out_indent_dec();
 554        }
 555}
 556
 557static void pr_out_entry_start(struct dl *dl)
 558{
 559        if (dl->json_output)
 560                open_json_object(NULL);
 561}
 562
 563static void pr_out_entry_end(struct dl *dl)
 564{
 565        if (dl->json_output)
 566                close_json_object();
 567        else
 568                __pr_out_newline();
 569}
 570
 571static void check_indent_newline(struct dl *dl)
 572{
 573        __pr_out_indent_newline(dl);
 574
 575        if (g_indent_newline && !is_json_context()) {
 576                printf("%s", g_indent_str);
 577                g_indent_newline = false;
 578        }
 579        g_new_line_count = 0;
 580}
 581
 582static const enum mnl_attr_data_type devlink_policy[DEVLINK_ATTR_MAX + 1] = {
 583        [DEVLINK_ATTR_BUS_NAME] = MNL_TYPE_NUL_STRING,
 584        [DEVLINK_ATTR_DEV_NAME] = MNL_TYPE_NUL_STRING,
 585        [DEVLINK_ATTR_PORT_INDEX] = MNL_TYPE_U32,
 586        [DEVLINK_ATTR_PORT_TYPE] = MNL_TYPE_U16,
 587        [DEVLINK_ATTR_PORT_DESIRED_TYPE] = MNL_TYPE_U16,
 588        [DEVLINK_ATTR_PORT_NETDEV_IFINDEX] = MNL_TYPE_U32,
 589        [DEVLINK_ATTR_PORT_NETDEV_NAME] = MNL_TYPE_NUL_STRING,
 590        [DEVLINK_ATTR_PORT_IBDEV_NAME] = MNL_TYPE_NUL_STRING,
 591        [DEVLINK_ATTR_PORT_LANES] = MNL_TYPE_U32,
 592        [DEVLINK_ATTR_PORT_SPLITTABLE] = MNL_TYPE_U8,
 593        [DEVLINK_ATTR_SB_INDEX] = MNL_TYPE_U32,
 594        [DEVLINK_ATTR_SB_SIZE] = MNL_TYPE_U32,
 595        [DEVLINK_ATTR_SB_INGRESS_POOL_COUNT] = MNL_TYPE_U16,
 596        [DEVLINK_ATTR_SB_EGRESS_POOL_COUNT] = MNL_TYPE_U16,
 597        [DEVLINK_ATTR_SB_INGRESS_TC_COUNT] = MNL_TYPE_U16,
 598        [DEVLINK_ATTR_SB_EGRESS_TC_COUNT] = MNL_TYPE_U16,
 599        [DEVLINK_ATTR_SB_POOL_INDEX] = MNL_TYPE_U16,
 600        [DEVLINK_ATTR_SB_POOL_TYPE] = MNL_TYPE_U8,
 601        [DEVLINK_ATTR_SB_POOL_SIZE] = MNL_TYPE_U32,
 602        [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = MNL_TYPE_U8,
 603        [DEVLINK_ATTR_SB_THRESHOLD] = MNL_TYPE_U32,
 604        [DEVLINK_ATTR_SB_TC_INDEX] = MNL_TYPE_U16,
 605        [DEVLINK_ATTR_SB_OCC_CUR] = MNL_TYPE_U32,
 606        [DEVLINK_ATTR_SB_OCC_MAX] = MNL_TYPE_U32,
 607        [DEVLINK_ATTR_ESWITCH_MODE] = MNL_TYPE_U16,
 608        [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = MNL_TYPE_U8,
 609        [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = MNL_TYPE_U8,
 610        [DEVLINK_ATTR_DPIPE_TABLES] = MNL_TYPE_NESTED,
 611        [DEVLINK_ATTR_DPIPE_TABLE] = MNL_TYPE_NESTED,
 612        [DEVLINK_ATTR_DPIPE_TABLE_NAME] = MNL_TYPE_STRING,
 613        [DEVLINK_ATTR_DPIPE_TABLE_SIZE] = MNL_TYPE_U64,
 614        [DEVLINK_ATTR_DPIPE_TABLE_MATCHES] = MNL_TYPE_NESTED,
 615        [DEVLINK_ATTR_DPIPE_TABLE_ACTIONS] = MNL_TYPE_NESTED,
 616        [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] =  MNL_TYPE_U8,
 617        [DEVLINK_ATTR_DPIPE_ENTRIES] = MNL_TYPE_NESTED,
 618        [DEVLINK_ATTR_DPIPE_ENTRY] = MNL_TYPE_NESTED,
 619        [DEVLINK_ATTR_DPIPE_ENTRY_INDEX] = MNL_TYPE_U64,
 620        [DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES] = MNL_TYPE_NESTED,
 621        [DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES] = MNL_TYPE_NESTED,
 622        [DEVLINK_ATTR_DPIPE_ENTRY_COUNTER] = MNL_TYPE_U64,
 623        [DEVLINK_ATTR_DPIPE_MATCH] = MNL_TYPE_NESTED,
 624        [DEVLINK_ATTR_DPIPE_MATCH_VALUE] = MNL_TYPE_NESTED,
 625        [DEVLINK_ATTR_DPIPE_MATCH_TYPE] = MNL_TYPE_U32,
 626        [DEVLINK_ATTR_DPIPE_ACTION] = MNL_TYPE_NESTED,
 627        [DEVLINK_ATTR_DPIPE_ACTION_VALUE] = MNL_TYPE_NESTED,
 628        [DEVLINK_ATTR_DPIPE_ACTION_TYPE] = MNL_TYPE_U32,
 629        [DEVLINK_ATTR_DPIPE_VALUE_MAPPING] = MNL_TYPE_U32,
 630        [DEVLINK_ATTR_DPIPE_HEADERS] = MNL_TYPE_NESTED,
 631        [DEVLINK_ATTR_DPIPE_HEADER] = MNL_TYPE_NESTED,
 632        [DEVLINK_ATTR_DPIPE_HEADER_NAME] = MNL_TYPE_STRING,
 633        [DEVLINK_ATTR_DPIPE_HEADER_ID] = MNL_TYPE_U32,
 634        [DEVLINK_ATTR_DPIPE_HEADER_FIELDS] = MNL_TYPE_NESTED,
 635        [DEVLINK_ATTR_DPIPE_HEADER_GLOBAL] = MNL_TYPE_U8,
 636        [DEVLINK_ATTR_DPIPE_HEADER_INDEX] = MNL_TYPE_U32,
 637        [DEVLINK_ATTR_DPIPE_FIELD] = MNL_TYPE_NESTED,
 638        [DEVLINK_ATTR_DPIPE_FIELD_NAME] = MNL_TYPE_STRING,
 639        [DEVLINK_ATTR_DPIPE_FIELD_ID] = MNL_TYPE_U32,
 640        [DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH] = MNL_TYPE_U32,
 641        [DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE] = MNL_TYPE_U32,
 642        [DEVLINK_ATTR_PARAM] = MNL_TYPE_NESTED,
 643        [DEVLINK_ATTR_PARAM_NAME] = MNL_TYPE_STRING,
 644        [DEVLINK_ATTR_PARAM_TYPE] = MNL_TYPE_U8,
 645        [DEVLINK_ATTR_PARAM_VALUES_LIST] = MNL_TYPE_NESTED,
 646        [DEVLINK_ATTR_PARAM_VALUE] = MNL_TYPE_NESTED,
 647        [DEVLINK_ATTR_PARAM_VALUE_CMODE] = MNL_TYPE_U8,
 648        [DEVLINK_ATTR_REGION_NAME] = MNL_TYPE_STRING,
 649        [DEVLINK_ATTR_REGION_SIZE] = MNL_TYPE_U64,
 650        [DEVLINK_ATTR_REGION_SNAPSHOTS] = MNL_TYPE_NESTED,
 651        [DEVLINK_ATTR_REGION_SNAPSHOT] = MNL_TYPE_NESTED,
 652        [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = MNL_TYPE_U32,
 653        [DEVLINK_ATTR_REGION_CHUNKS] = MNL_TYPE_NESTED,
 654        [DEVLINK_ATTR_REGION_CHUNK] = MNL_TYPE_NESTED,
 655        [DEVLINK_ATTR_REGION_CHUNK_DATA] = MNL_TYPE_BINARY,
 656        [DEVLINK_ATTR_REGION_CHUNK_ADDR] = MNL_TYPE_U64,
 657        [DEVLINK_ATTR_REGION_CHUNK_LEN] = MNL_TYPE_U64,
 658        [DEVLINK_ATTR_INFO_DRIVER_NAME] = MNL_TYPE_STRING,
 659        [DEVLINK_ATTR_INFO_SERIAL_NUMBER] = MNL_TYPE_STRING,
 660        [DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER] = MNL_TYPE_STRING,
 661        [DEVLINK_ATTR_INFO_VERSION_FIXED] = MNL_TYPE_NESTED,
 662        [DEVLINK_ATTR_INFO_VERSION_RUNNING] = MNL_TYPE_NESTED,
 663        [DEVLINK_ATTR_INFO_VERSION_STORED] = MNL_TYPE_NESTED,
 664        [DEVLINK_ATTR_INFO_VERSION_NAME] = MNL_TYPE_STRING,
 665        [DEVLINK_ATTR_INFO_VERSION_VALUE] = MNL_TYPE_STRING,
 666        [DEVLINK_ATTR_HEALTH_REPORTER] = MNL_TYPE_NESTED,
 667        [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = MNL_TYPE_STRING,
 668        [DEVLINK_ATTR_HEALTH_REPORTER_STATE] = MNL_TYPE_U8,
 669        [DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT] = MNL_TYPE_U64,
 670        [DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT] = MNL_TYPE_U64,
 671        [DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS] = MNL_TYPE_U64,
 672        [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = MNL_TYPE_U64,
 673        [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT] = MNL_TYPE_STRING,
 674        [DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG] = MNL_TYPE_STRING,
 675        [DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE] = MNL_TYPE_U64,
 676        [DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL] = MNL_TYPE_U64,
 677        [DEVLINK_ATTR_STATS] = MNL_TYPE_NESTED,
 678        [DEVLINK_ATTR_TRAP_NAME] = MNL_TYPE_STRING,
 679        [DEVLINK_ATTR_TRAP_ACTION] = MNL_TYPE_U8,
 680        [DEVLINK_ATTR_TRAP_TYPE] = MNL_TYPE_U8,
 681        [DEVLINK_ATTR_TRAP_GENERIC] = MNL_TYPE_FLAG,
 682        [DEVLINK_ATTR_TRAP_METADATA] = MNL_TYPE_NESTED,
 683        [DEVLINK_ATTR_TRAP_GROUP_NAME] = MNL_TYPE_STRING,
 684        [DEVLINK_ATTR_RELOAD_FAILED] = MNL_TYPE_U8,
 685        [DEVLINK_ATTR_DEV_STATS] = MNL_TYPE_NESTED,
 686        [DEVLINK_ATTR_RELOAD_STATS] = MNL_TYPE_NESTED,
 687        [DEVLINK_ATTR_RELOAD_STATS_ENTRY] = MNL_TYPE_NESTED,
 688        [DEVLINK_ATTR_RELOAD_ACTION] = MNL_TYPE_U8,
 689        [DEVLINK_ATTR_RELOAD_STATS_LIMIT] = MNL_TYPE_U8,
 690        [DEVLINK_ATTR_RELOAD_STATS_VALUE] = MNL_TYPE_U32,
 691        [DEVLINK_ATTR_REMOTE_RELOAD_STATS] = MNL_TYPE_NESTED,
 692        [DEVLINK_ATTR_RELOAD_ACTION_INFO] = MNL_TYPE_NESTED,
 693        [DEVLINK_ATTR_RELOAD_ACTION_STATS] = MNL_TYPE_NESTED,
 694        [DEVLINK_ATTR_TRAP_POLICER_ID] = MNL_TYPE_U32,
 695        [DEVLINK_ATTR_TRAP_POLICER_RATE] = MNL_TYPE_U64,
 696        [DEVLINK_ATTR_TRAP_POLICER_BURST] = MNL_TYPE_U64,
 697};
 698
 699static const enum mnl_attr_data_type
 700devlink_stats_policy[DEVLINK_ATTR_STATS_MAX + 1] = {
 701        [DEVLINK_ATTR_STATS_RX_PACKETS] = MNL_TYPE_U64,
 702        [DEVLINK_ATTR_STATS_RX_BYTES] = MNL_TYPE_U64,
 703        [DEVLINK_ATTR_STATS_RX_DROPPED] = MNL_TYPE_U64,
 704};
 705
 706static int attr_cb(const struct nlattr *attr, void *data)
 707{
 708        const struct nlattr **tb = data;
 709        int type;
 710
 711        if (mnl_attr_type_valid(attr, DEVLINK_ATTR_MAX) < 0)
 712                return MNL_CB_OK;
 713
 714        type = mnl_attr_get_type(attr);
 715        if (mnl_attr_validate(attr, devlink_policy[type]) < 0)
 716                return MNL_CB_ERROR;
 717
 718        tb[type] = attr;
 719        return MNL_CB_OK;
 720}
 721
 722static int attr_stats_cb(const struct nlattr *attr, void *data)
 723{
 724        const struct nlattr **tb = data;
 725        int type;
 726
 727        /* Allow the tool to work on top of newer kernels that might contain
 728         * more attributes.
 729         */
 730        if (mnl_attr_type_valid(attr, DEVLINK_ATTR_STATS_MAX) < 0)
 731                return MNL_CB_OK;
 732
 733        type = mnl_attr_get_type(attr);
 734        if (mnl_attr_validate(attr, devlink_stats_policy[type]) < 0)
 735                return MNL_CB_ERROR;
 736
 737        tb[type] = attr;
 738        return MNL_CB_OK;
 739}
 740
 741static const enum mnl_attr_data_type
 742devlink_function_policy[DEVLINK_PORT_FUNCTION_ATTR_MAX + 1] = {
 743        [DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR ] = MNL_TYPE_BINARY,
 744};
 745
 746static int function_attr_cb(const struct nlattr *attr, void *data)
 747{
 748        const struct nlattr **tb = data;
 749        int type;
 750
 751        /* Allow the tool to work on top of newer kernels that might contain
 752         * more attributes.
 753         */
 754        if (mnl_attr_type_valid(attr, DEVLINK_PORT_FUNCTION_ATTR_MAX) < 0)
 755                return MNL_CB_OK;
 756
 757        type = mnl_attr_get_type(attr);
 758        if (mnl_attr_validate(attr, devlink_function_policy[type]) < 0)
 759                return MNL_CB_ERROR;
 760
 761        tb[type] = attr;
 762        return MNL_CB_OK;
 763}
 764
 765static int ifname_map_cb(const struct nlmsghdr *nlh, void *data)
 766{
 767        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
 768        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
 769        struct dl *dl = data;
 770        struct ifname_map *ifname_map;
 771        const char *bus_name;
 772        const char *dev_name;
 773        uint32_t port_ifindex;
 774        const char *port_ifname;
 775
 776        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
 777        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
 778            !tb[DEVLINK_ATTR_PORT_INDEX])
 779                return MNL_CB_ERROR;
 780
 781        if (!tb[DEVLINK_ATTR_PORT_NETDEV_NAME])
 782                return MNL_CB_OK;
 783
 784        bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
 785        dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
 786        port_ifindex = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]);
 787        port_ifname = mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME]);
 788        ifname_map = ifname_map_alloc(bus_name, dev_name,
 789                                      port_ifindex, port_ifname);
 790        if (!ifname_map)
 791                return MNL_CB_ERROR;
 792        list_add(&ifname_map->list, &dl->ifname_map_list);
 793
 794        return MNL_CB_OK;
 795}
 796
 797static void ifname_map_fini(struct dl *dl)
 798{
 799        struct ifname_map *ifname_map, *tmp;
 800
 801        list_for_each_entry_safe(ifname_map, tmp,
 802                                 &dl->ifname_map_list, list) {
 803                list_del(&ifname_map->list);
 804                ifname_map_free(ifname_map);
 805        }
 806}
 807
 808static int ifname_map_init(struct dl *dl)
 809{
 810        struct nlmsghdr *nlh;
 811        int err;
 812
 813        INIT_LIST_HEAD(&dl->ifname_map_list);
 814
 815        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_GET,
 816                               NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
 817
 818        err = _mnlg_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 unsigned int strslashcount(char *str)
 861{
 862        unsigned int count = 0;
 863        char *pos = str;
 864
 865        while ((pos = strchr(pos, '/'))) {
 866                count++;
 867                pos++;
 868        }
 869        return count;
 870}
 871
 872static int strslashrsplit(char *str, char **before, char **after)
 873{
 874        char *slash;
 875
 876        slash = strrchr(str, '/');
 877        if (!slash)
 878                return -EINVAL;
 879        *slash = '\0';
 880        *before = str;
 881        *after = slash + 1;
 882        return 0;
 883}
 884
 885static int strtouint64_t(const char *str, uint64_t *p_val)
 886{
 887        char *endptr;
 888        unsigned long long int val;
 889
 890        val = strtoull(str, &endptr, 10);
 891        if (endptr == str || *endptr != '\0')
 892                return -EINVAL;
 893        if (val > ULONG_MAX)
 894                return -ERANGE;
 895        *p_val = val;
 896        return 0;
 897}
 898
 899static int strtouint32_t(const char *str, uint32_t *p_val)
 900{
 901        char *endptr;
 902        unsigned long int val;
 903
 904        val = strtoul(str, &endptr, 10);
 905        if (endptr == str || *endptr != '\0')
 906                return -EINVAL;
 907        if (val > UINT_MAX)
 908                return -ERANGE;
 909        *p_val = val;
 910        return 0;
 911}
 912
 913static int strtouint16_t(const char *str, uint16_t *p_val)
 914{
 915        char *endptr;
 916        unsigned long int val;
 917
 918        val = strtoul(str, &endptr, 10);
 919        if (endptr == str || *endptr != '\0')
 920                return -EINVAL;
 921        if (val > USHRT_MAX)
 922                return -ERANGE;
 923        *p_val = val;
 924        return 0;
 925}
 926
 927static int strtouint8_t(const char *str, uint8_t *p_val)
 928{
 929        char *endptr;
 930        unsigned long int val;
 931
 932        val = strtoul(str, &endptr, 10);
 933        if (endptr == str || *endptr != '\0')
 934                return -EINVAL;
 935        if (val > UCHAR_MAX)
 936                return -ERANGE;
 937        *p_val = val;
 938        return 0;
 939}
 940
 941static int strtobool(const char *str, bool *p_val)
 942{
 943        bool val;
 944
 945        if (!strcmp(str, "true") || !strcmp(str, "1") ||
 946            !strcmp(str, "enable"))
 947                val = true;
 948        else if (!strcmp(str, "false") || !strcmp(str, "0") ||
 949                 !strcmp(str, "disable"))
 950                val = false;
 951        else
 952                return -EINVAL;
 953        *p_val = val;
 954        return 0;
 955}
 956
 957static int __dl_argv_handle(char *str, char **p_bus_name, char **p_dev_name)
 958{
 959        strslashrsplit(str, p_bus_name, p_dev_name);
 960        return 0;
 961}
 962
 963static int dl_argv_handle(struct dl *dl, char **p_bus_name, char **p_dev_name)
 964{
 965        char *str = dl_argv_next(dl);
 966
 967        if (!str) {
 968                pr_err("Devlink identification (\"bus_name/dev_name\") expected\n");
 969                return -EINVAL;
 970        }
 971        if (strslashcount(str) != 1) {
 972                pr_err("Wrong devlink identification string format.\n");
 973                pr_err("Expected \"bus_name/dev_name\".\n");
 974                return -EINVAL;
 975        }
 976        return __dl_argv_handle(str, p_bus_name, p_dev_name);
 977}
 978
 979static int __dl_argv_handle_port(char *str,
 980                                 char **p_bus_name, char **p_dev_name,
 981                                 uint32_t *p_port_index)
 982{
 983        char *handlestr;
 984        char *portstr;
 985        int err;
 986
 987        err = strslashrsplit(str, &handlestr, &portstr);
 988        if (err) {
 989                pr_err("Port identification \"%s\" is invalid\n", str);
 990                return err;
 991        }
 992        err = strtouint32_t(portstr, p_port_index);
 993        if (err) {
 994                pr_err("Port index \"%s\" is not a number or not within range\n",
 995                       portstr);
 996                return err;
 997        }
 998        err = strslashrsplit(handlestr, p_bus_name, p_dev_name);
 999        if (err) {
1000                pr_err("Port identification \"%s\" is invalid\n", str);
1001                return err;
1002        }
1003        return 0;
1004}
1005
1006static int __dl_argv_handle_port_ifname(struct dl *dl, char *str,
1007                                        char **p_bus_name, char **p_dev_name,
1008                                        uint32_t *p_port_index)
1009{
1010        int err;
1011
1012        err = ifname_map_lookup(dl, str, p_bus_name, p_dev_name,
1013                                p_port_index);
1014        if (err) {
1015                pr_err("Netdevice \"%s\" not found\n", str);
1016                return err;
1017        }
1018        return 0;
1019}
1020
1021static int dl_argv_handle_port(struct dl *dl, char **p_bus_name,
1022                               char **p_dev_name, uint32_t *p_port_index)
1023{
1024        char *str = dl_argv_next(dl);
1025        unsigned int slash_count;
1026
1027        if (!str) {
1028                pr_err("Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\") expected.\n");
1029                return -EINVAL;
1030        }
1031        slash_count = strslashcount(str);
1032        switch (slash_count) {
1033        case 0:
1034                return __dl_argv_handle_port_ifname(dl, str, p_bus_name,
1035                                                    p_dev_name, p_port_index);
1036        case 2:
1037                return __dl_argv_handle_port(str, p_bus_name,
1038                                             p_dev_name, p_port_index);
1039        default:
1040                pr_err("Wrong port identification string format.\n");
1041                pr_err("Expected \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
1042                return -EINVAL;
1043        }
1044}
1045
1046static int dl_argv_handle_both(struct dl *dl, char **p_bus_name,
1047                               char **p_dev_name, uint32_t *p_port_index,
1048                               uint64_t *p_handle_bit)
1049{
1050        char *str = dl_argv_next(dl);
1051        unsigned int slash_count;
1052        int err;
1053
1054        if (!str) {
1055                pr_err("One of following identifications expected:\n"
1056                       "Devlink identification (\"bus_name/dev_name\")\n"
1057                       "Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\")\n");
1058                return -EINVAL;
1059        }
1060        slash_count = strslashcount(str);
1061        if (slash_count == 1) {
1062                err = __dl_argv_handle(str, p_bus_name, p_dev_name);
1063                if (err)
1064                        return err;
1065                *p_handle_bit = DL_OPT_HANDLE;
1066        } else if (slash_count == 2) {
1067                err = __dl_argv_handle_port(str, p_bus_name,
1068                                            p_dev_name, p_port_index);
1069                if (err)
1070                        return err;
1071                *p_handle_bit = DL_OPT_HANDLEP;
1072        } else if (slash_count == 0) {
1073                err = __dl_argv_handle_port_ifname(dl, str, p_bus_name,
1074                                                   p_dev_name, p_port_index);
1075                if (err)
1076                        return err;
1077                *p_handle_bit = DL_OPT_HANDLEP;
1078        } else {
1079                pr_err("Wrong port identification string format.\n");
1080                pr_err("Expected \"bus_name/dev_name\" or \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
1081                return -EINVAL;
1082        }
1083        return 0;
1084}
1085
1086static int __dl_argv_handle_region(char *str, char **p_bus_name,
1087                                   char **p_dev_name, char **p_region)
1088{
1089        char *handlestr;
1090        int err;
1091
1092        err = strslashrsplit(str, &handlestr, p_region);
1093        if (err) {
1094                pr_err("Region identification \"%s\" is invalid\n", str);
1095                return err;
1096        }
1097        err = strslashrsplit(handlestr, p_bus_name, p_dev_name);
1098        if (err) {
1099                pr_err("Region identification \"%s\" is invalid\n", str);
1100                return err;
1101        }
1102        return 0;
1103}
1104
1105static int dl_argv_handle_region(struct dl *dl, char **p_bus_name,
1106                                        char **p_dev_name, char **p_region)
1107{
1108        char *str = dl_argv_next(dl);
1109        unsigned int slash_count;
1110
1111        if (!str) {
1112                pr_err("Expected \"bus_name/dev_name/region\" identification.\n");
1113                return -EINVAL;
1114        }
1115
1116        slash_count = strslashcount(str);
1117        if (slash_count != 2) {
1118                pr_err("Wrong region identification string format.\n");
1119                pr_err("Expected \"bus_name/dev_name/region\" identification.\n"".\n");
1120                return -EINVAL;
1121        }
1122
1123        return __dl_argv_handle_region(str, p_bus_name, p_dev_name, p_region);
1124}
1125
1126static int dl_argv_uint64_t(struct dl *dl, uint64_t *p_val)
1127{
1128        char *str = dl_argv_next(dl);
1129        int err;
1130
1131        if (!str) {
1132                pr_err("Unsigned number argument expected\n");
1133                return -EINVAL;
1134        }
1135
1136        err = strtouint64_t(str, p_val);
1137        if (err) {
1138                pr_err("\"%s\" is not a number or not within range\n", str);
1139                return err;
1140        }
1141        return 0;
1142}
1143
1144static int dl_argv_uint32_t(struct dl *dl, uint32_t *p_val)
1145{
1146        char *str = dl_argv_next(dl);
1147        int err;
1148
1149        if (!str) {
1150                pr_err("Unsigned number argument expected\n");
1151                return -EINVAL;
1152        }
1153
1154        err = strtouint32_t(str, p_val);
1155        if (err) {
1156                pr_err("\"%s\" is not a number or not within range\n", str);
1157                return err;
1158        }
1159        return 0;
1160}
1161
1162static int dl_argv_uint16_t(struct dl *dl, uint16_t *p_val)
1163{
1164        char *str = dl_argv_next(dl);
1165        int err;
1166
1167        if (!str) {
1168                pr_err("Unsigned number argument expected\n");
1169                return -EINVAL;
1170        }
1171
1172        err = strtouint16_t(str, p_val);
1173        if (err) {
1174                pr_err("\"%s\" is not a number or not within range\n", str);
1175                return err;
1176        }
1177        return 0;
1178}
1179
1180static int dl_argv_bool(struct dl *dl, bool *p_val)
1181{
1182        char *str = dl_argv_next(dl);
1183        int err;
1184
1185        if (!str) {
1186                pr_err("Boolean argument expected\n");
1187                return -EINVAL;
1188        }
1189
1190        err = strtobool(str, p_val);
1191        if (err) {
1192                pr_err("\"%s\" is not a valid boolean value\n", str);
1193                return err;
1194        }
1195        return 0;
1196}
1197
1198static int dl_argv_str(struct dl *dl, const char **p_str)
1199{
1200        const char *str = dl_argv_next(dl);
1201
1202        if (!str) {
1203                pr_err("String parameter expected\n");
1204                return -EINVAL;
1205        }
1206        *p_str = str;
1207        return 0;
1208}
1209
1210static int port_type_get(const char *typestr, enum devlink_port_type *p_type)
1211{
1212        if (strcmp(typestr, "auto") == 0) {
1213                *p_type = DEVLINK_PORT_TYPE_AUTO;
1214        } else if (strcmp(typestr, "eth") == 0) {
1215                *p_type = DEVLINK_PORT_TYPE_ETH;
1216        } else if (strcmp(typestr, "ib") == 0) {
1217                *p_type = DEVLINK_PORT_TYPE_IB;
1218        } else {
1219                pr_err("Unknown port type \"%s\"\n", typestr);
1220                return -EINVAL;
1221        }
1222        return 0;
1223}
1224
1225static int pool_type_get(const char *typestr, enum devlink_sb_pool_type *p_type)
1226{
1227        if (strcmp(typestr, "ingress") == 0) {
1228                *p_type = DEVLINK_SB_POOL_TYPE_INGRESS;
1229        } else if (strcmp(typestr, "egress") == 0) {
1230                *p_type = DEVLINK_SB_POOL_TYPE_EGRESS;
1231        } else {
1232                pr_err("Unknown pool type \"%s\"\n", typestr);
1233                return -EINVAL;
1234        }
1235        return 0;
1236}
1237
1238static int threshold_type_get(const char *typestr,
1239                              enum devlink_sb_threshold_type *p_type)
1240{
1241        if (strcmp(typestr, "static") == 0) {
1242                *p_type = DEVLINK_SB_THRESHOLD_TYPE_STATIC;
1243        } else if (strcmp(typestr, "dynamic") == 0) {
1244                *p_type = DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC;
1245        } else {
1246                pr_err("Unknown threshold type \"%s\"\n", typestr);
1247                return -EINVAL;
1248        }
1249        return 0;
1250}
1251
1252static int eswitch_mode_get(const char *typestr,
1253                            enum devlink_eswitch_mode *p_mode)
1254{
1255        if (strcmp(typestr, ESWITCH_MODE_LEGACY) == 0) {
1256                *p_mode = DEVLINK_ESWITCH_MODE_LEGACY;
1257        } else if (strcmp(typestr, ESWITCH_MODE_SWITCHDEV) == 0) {
1258                *p_mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
1259        } else {
1260                pr_err("Unknown eswitch mode \"%s\"\n", typestr);
1261                return -EINVAL;
1262        }
1263        return 0;
1264}
1265
1266static int eswitch_inline_mode_get(const char *typestr,
1267                                   enum devlink_eswitch_inline_mode *p_mode)
1268{
1269        if (strcmp(typestr, ESWITCH_INLINE_MODE_NONE) == 0) {
1270                *p_mode = DEVLINK_ESWITCH_INLINE_MODE_NONE;
1271        } else if (strcmp(typestr, ESWITCH_INLINE_MODE_LINK) == 0) {
1272                *p_mode = DEVLINK_ESWITCH_INLINE_MODE_LINK;
1273        } else if (strcmp(typestr, ESWITCH_INLINE_MODE_NETWORK) == 0) {
1274                *p_mode = DEVLINK_ESWITCH_INLINE_MODE_NETWORK;
1275        } else if (strcmp(typestr, ESWITCH_INLINE_MODE_TRANSPORT) == 0) {
1276                *p_mode = DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT;
1277        } else {
1278                pr_err("Unknown eswitch inline mode \"%s\"\n", typestr);
1279                return -EINVAL;
1280        }
1281        return 0;
1282}
1283
1284static int
1285eswitch_encap_mode_get(const char *typestr,
1286                       enum devlink_eswitch_encap_mode *p_encap_mode)
1287{
1288        /* The initial implementation incorrectly accepted "enable"/"disable".
1289         * Carry it to maintain backward compatibility.
1290         */
1291        if (strcmp(typestr, "disable") == 0 ||
1292                   strcmp(typestr, ESWITCH_ENCAP_MODE_NONE) == 0) {
1293                *p_encap_mode = DEVLINK_ESWITCH_ENCAP_MODE_NONE;
1294        } else if (strcmp(typestr, "enable") == 0 ||
1295                   strcmp(typestr, ESWITCH_ENCAP_MODE_BASIC) == 0) {
1296                *p_encap_mode = DEVLINK_ESWITCH_ENCAP_MODE_BASIC;
1297        } else {
1298                pr_err("Unknown eswitch encap mode \"%s\"\n", typestr);
1299                return -EINVAL;
1300        }
1301        return 0;
1302}
1303
1304static int flash_overwrite_section_get(const char *sectionstr, uint32_t *mask)
1305{
1306        if (strcmp(sectionstr, "settings") == 0) {
1307                *mask |= DEVLINK_FLASH_OVERWRITE_SETTINGS;
1308        } else if (strcmp(sectionstr, "identifiers") == 0) {
1309                *mask |= DEVLINK_FLASH_OVERWRITE_IDENTIFIERS;
1310        } else {
1311                pr_err("Unknown overwrite section \"%s\"\n", sectionstr);
1312                return -EINVAL;
1313        }
1314        return 0;
1315}
1316
1317static int param_cmode_get(const char *cmodestr,
1318                           enum devlink_param_cmode *cmode)
1319{
1320        if (strcmp(cmodestr, PARAM_CMODE_RUNTIME_STR) == 0) {
1321                *cmode = DEVLINK_PARAM_CMODE_RUNTIME;
1322        } else if (strcmp(cmodestr, PARAM_CMODE_DRIVERINIT_STR) == 0) {
1323                *cmode = DEVLINK_PARAM_CMODE_DRIVERINIT;
1324        } else if (strcmp(cmodestr, PARAM_CMODE_PERMANENT_STR) == 0) {
1325                *cmode = DEVLINK_PARAM_CMODE_PERMANENT;
1326        } else {
1327                pr_err("Unknown configuration mode \"%s\"\n", cmodestr);
1328                return -EINVAL;
1329        }
1330        return 0;
1331}
1332
1333static int trap_action_get(const char *actionstr,
1334                           enum devlink_trap_action *p_action)
1335{
1336        if (strcmp(actionstr, "drop") == 0) {
1337                *p_action = DEVLINK_TRAP_ACTION_DROP;
1338        } else if (strcmp(actionstr, "trap") == 0) {
1339                *p_action = DEVLINK_TRAP_ACTION_TRAP;
1340        } else if (strcmp(actionstr, "mirror") == 0) {
1341                *p_action = DEVLINK_TRAP_ACTION_MIRROR;
1342        } else {
1343                pr_err("Unknown trap action \"%s\"\n", actionstr);
1344                return -EINVAL;
1345        }
1346        return 0;
1347}
1348
1349static int hw_addr_parse(const char *addrstr, char *hw_addr, uint32_t *len)
1350{
1351        int alen;
1352
1353        alen = ll_addr_a2n(hw_addr, MAX_ADDR_LEN, addrstr);
1354        if (alen < 0)
1355                return -EINVAL;
1356        *len = alen;
1357        return 0;
1358}
1359
1360static int reload_action_get(struct dl *dl, const char *actionstr,
1361                             enum devlink_reload_action *action)
1362{
1363        if (strcmp(actionstr, "driver_reinit") == 0) {
1364                *action = DEVLINK_RELOAD_ACTION_DRIVER_REINIT;
1365        } else if (strcmp(actionstr, "fw_activate") == 0) {
1366                *action = DEVLINK_RELOAD_ACTION_FW_ACTIVATE;
1367        } else {
1368                pr_err("Unknown reload action \"%s\"\n", actionstr);
1369                return -EINVAL;
1370        }
1371        return 0;
1372}
1373
1374static int reload_limit_get(struct dl *dl, const char *limitstr,
1375                             enum devlink_reload_limit *limit)
1376{
1377        if (strcmp(limitstr, "no_reset") == 0) {
1378                *limit = DEVLINK_RELOAD_LIMIT_NO_RESET;
1379        } else {
1380                pr_err("Unknown reload limit \"%s\"\n", limitstr);
1381                return -EINVAL;
1382        }
1383        return 0;
1384}
1385
1386struct dl_args_metadata {
1387        uint64_t o_flag;
1388        char err_msg[DL_ARGS_REQUIRED_MAX_ERR_LEN];
1389};
1390
1391static const struct dl_args_metadata dl_args_required[] = {
1392        {DL_OPT_PORT_TYPE,            "Port type not set."},
1393        {DL_OPT_PORT_COUNT,           "Port split count option expected."},
1394        {DL_OPT_SB_POOL,              "Pool index option expected."},
1395        {DL_OPT_SB_SIZE,              "Pool size option expected."},
1396        {DL_OPT_SB_TYPE,              "Pool type option expected."},
1397        {DL_OPT_SB_THTYPE,            "Pool threshold type option expected."},
1398        {DL_OPT_SB_TH,                "Threshold option expected."},
1399        {DL_OPT_SB_TC,                "TC index option expected."},
1400        {DL_OPT_ESWITCH_MODE,         "E-Switch mode option expected."},
1401        {DL_OPT_ESWITCH_INLINE_MODE,  "E-Switch inline-mode option expected."},
1402        {DL_OPT_DPIPE_TABLE_NAME,     "Dpipe table name expected."},
1403        {DL_OPT_DPIPE_TABLE_COUNTERS, "Dpipe table counter state expected."},
1404        {DL_OPT_ESWITCH_ENCAP_MODE,   "E-Switch encapsulation option expected."},
1405        {DL_OPT_RESOURCE_PATH,        "Resource path expected."},
1406        {DL_OPT_RESOURCE_SIZE,        "Resource size expected."},
1407        {DL_OPT_PARAM_NAME,           "Parameter name expected."},
1408        {DL_OPT_PARAM_VALUE,          "Value to set expected."},
1409        {DL_OPT_PARAM_CMODE,          "Configuration mode expected."},
1410        {DL_OPT_REGION_SNAPSHOT_ID,   "Region snapshot id expected."},
1411        {DL_OPT_REGION_ADDRESS,       "Region address value expected."},
1412        {DL_OPT_REGION_LENGTH,        "Region length value expected."},
1413        {DL_OPT_HEALTH_REPORTER_NAME, "Reporter's name is expected."},
1414        {DL_OPT_TRAP_NAME,            "Trap's name is expected."},
1415        {DL_OPT_TRAP_GROUP_NAME,      "Trap group's name is expected."},
1416        {DL_OPT_PORT_FUNCTION_HW_ADDR, "Port function's hardware address is expected."},
1417};
1418
1419static int dl_args_finding_required_validate(uint64_t o_required,
1420                                             uint64_t o_found)
1421{
1422        uint64_t o_flag;
1423        int i;
1424
1425        for (i = 0; i < ARRAY_SIZE(dl_args_required); i++) {
1426                o_flag = dl_args_required[i].o_flag;
1427                if ((o_required & o_flag) && !(o_found & o_flag)) {
1428                        pr_err("%s\n", dl_args_required[i].err_msg);
1429                        return -EINVAL;
1430                }
1431        }
1432        if (o_required & ~o_found) {
1433                pr_err("BUG: unknown argument required but not found\n");
1434                return -EINVAL;
1435        }
1436        return 0;
1437}
1438
1439static int dl_argv_parse(struct dl *dl, uint64_t o_required,
1440                         uint64_t o_optional)
1441{
1442        struct dl_opts *opts = &dl->opts;
1443        uint64_t o_all = o_required | o_optional;
1444        uint64_t o_found = 0;
1445        int err;
1446
1447        if (o_required & DL_OPT_HANDLE && o_required & DL_OPT_HANDLEP) {
1448                uint64_t handle_bit;
1449
1450                err = dl_argv_handle_both(dl, &opts->bus_name, &opts->dev_name,
1451                                          &opts->port_index, &handle_bit);
1452                if (err)
1453                        return err;
1454                o_required &= ~(DL_OPT_HANDLE | DL_OPT_HANDLEP) | handle_bit;
1455                o_found |= handle_bit;
1456        } else if (o_required & DL_OPT_HANDLE) {
1457                err = dl_argv_handle(dl, &opts->bus_name, &opts->dev_name);
1458                if (err)
1459                        return err;
1460                o_found |= DL_OPT_HANDLE;
1461        } else if (o_required & DL_OPT_HANDLEP) {
1462                err = dl_argv_handle_port(dl, &opts->bus_name, &opts->dev_name,
1463                                          &opts->port_index);
1464                if (err)
1465                        return err;
1466                o_found |= DL_OPT_HANDLEP;
1467        } else if (o_required & DL_OPT_HANDLE_REGION) {
1468                err = dl_argv_handle_region(dl, &opts->bus_name,
1469                                            &opts->dev_name,
1470                                            &opts->region_name);
1471                if (err)
1472                        return err;
1473                o_found |= DL_OPT_HANDLE_REGION;
1474        }
1475
1476        while (dl_argc(dl)) {
1477                if (dl_argv_match(dl, "type") &&
1478                    (o_all & DL_OPT_PORT_TYPE)) {
1479                        const char *typestr;
1480
1481                        dl_arg_inc(dl);
1482                        err = dl_argv_str(dl, &typestr);
1483                        if (err)
1484                                return err;
1485                        err = port_type_get(typestr, &opts->port_type);
1486                        if (err)
1487                                return err;
1488                        o_found |= DL_OPT_PORT_TYPE;
1489                } else if (dl_argv_match(dl, "count") &&
1490                           (o_all & DL_OPT_PORT_COUNT)) {
1491                        dl_arg_inc(dl);
1492                        err = dl_argv_uint32_t(dl, &opts->port_count);
1493                        if (err)
1494                                return err;
1495                        o_found |= DL_OPT_PORT_COUNT;
1496                } else if (dl_argv_match(dl, "sb") &&
1497                           (o_all & DL_OPT_SB)) {
1498                        dl_arg_inc(dl);
1499                        err = dl_argv_uint32_t(dl, &opts->sb_index);
1500                        if (err)
1501                                return err;
1502                        o_found |= DL_OPT_SB;
1503                } else if (dl_argv_match(dl, "pool") &&
1504                           (o_all & DL_OPT_SB_POOL)) {
1505                        dl_arg_inc(dl);
1506                        err = dl_argv_uint16_t(dl, &opts->sb_pool_index);
1507                        if (err)
1508                                return err;
1509                        o_found |= DL_OPT_SB_POOL;
1510                } else if (dl_argv_match(dl, "size") &&
1511                           (o_all & DL_OPT_SB_SIZE)) {
1512                        dl_arg_inc(dl);
1513                        err = dl_argv_uint32_t(dl, &opts->sb_pool_size);
1514                        if (err)
1515                                return err;
1516                        o_found |= DL_OPT_SB_SIZE;
1517                } else if (dl_argv_match(dl, "type") &&
1518                           (o_all & DL_OPT_SB_TYPE)) {
1519                        const char *typestr;
1520
1521                        dl_arg_inc(dl);
1522                        err = dl_argv_str(dl, &typestr);
1523                        if (err)
1524                                return err;
1525                        err = pool_type_get(typestr, &opts->sb_pool_type);
1526                        if (err)
1527                                return err;
1528                        o_found |= DL_OPT_SB_TYPE;
1529                } else if (dl_argv_match(dl, "thtype") &&
1530                           (o_all & DL_OPT_SB_THTYPE)) {
1531                        const char *typestr;
1532
1533                        dl_arg_inc(dl);
1534                        err = dl_argv_str(dl, &typestr);
1535                        if (err)
1536                                return err;
1537                        err = threshold_type_get(typestr,
1538                                                 &opts->sb_pool_thtype);
1539                        if (err)
1540                                return err;
1541                        o_found |= DL_OPT_SB_THTYPE;
1542                } else if (dl_argv_match(dl, "th") &&
1543                           (o_all & DL_OPT_SB_TH)) {
1544                        dl_arg_inc(dl);
1545                        err = dl_argv_uint32_t(dl, &opts->sb_threshold);
1546                        if (err)
1547                                return err;
1548                        o_found |= DL_OPT_SB_TH;
1549                } else if (dl_argv_match(dl, "tc") &&
1550                           (o_all & DL_OPT_SB_TC)) {
1551                        dl_arg_inc(dl);
1552                        err = dl_argv_uint16_t(dl, &opts->sb_tc_index);
1553                        if (err)
1554                                return err;
1555                        o_found |= DL_OPT_SB_TC;
1556                } else if (dl_argv_match(dl, "mode") &&
1557                           (o_all & DL_OPT_ESWITCH_MODE)) {
1558                        const char *typestr;
1559
1560                        dl_arg_inc(dl);
1561                        err = dl_argv_str(dl, &typestr);
1562                        if (err)
1563                                return err;
1564                        err = eswitch_mode_get(typestr, &opts->eswitch_mode);
1565                        if (err)
1566                                return err;
1567                        o_found |= DL_OPT_ESWITCH_MODE;
1568                } else if (dl_argv_match(dl, "inline-mode") &&
1569                           (o_all & DL_OPT_ESWITCH_INLINE_MODE)) {
1570                        const char *typestr;
1571
1572                        dl_arg_inc(dl);
1573                        err = dl_argv_str(dl, &typestr);
1574                        if (err)
1575                                return err;
1576                        err = eswitch_inline_mode_get(
1577                                typestr, &opts->eswitch_inline_mode);
1578                        if (err)
1579                                return err;
1580                        o_found |= DL_OPT_ESWITCH_INLINE_MODE;
1581                } else if (dl_argv_match(dl, "name") &&
1582                           (o_all & DL_OPT_DPIPE_TABLE_NAME)) {
1583                        dl_arg_inc(dl);
1584                        err = dl_argv_str(dl, &opts->dpipe_table_name);
1585                        if (err)
1586                                return err;
1587                        o_found |= DL_OPT_DPIPE_TABLE_NAME;
1588                } else if ((dl_argv_match(dl, "counters") ||
1589                            dl_argv_match(dl, "counters_enabled")) &&
1590                           (o_all & DL_OPT_DPIPE_TABLE_COUNTERS)) {
1591                        dl_arg_inc(dl);
1592                        err = dl_argv_bool(dl, &opts->dpipe_counters_enabled);
1593                        if (err)
1594                                return err;
1595                        o_found |= DL_OPT_DPIPE_TABLE_COUNTERS;
1596                } else if ((dl_argv_match(dl, "encap") || /* Original incorrect implementation */
1597                            dl_argv_match(dl, "encap-mode")) &&
1598                           (o_all & DL_OPT_ESWITCH_ENCAP_MODE)) {
1599                        const char *typestr;
1600
1601                        dl_arg_inc(dl);
1602                        err = dl_argv_str(dl, &typestr);
1603                        if (err)
1604                                return err;
1605                        err = eswitch_encap_mode_get(typestr,
1606                                                     &opts->eswitch_encap_mode);
1607                        if (err)
1608                                return err;
1609                        o_found |= DL_OPT_ESWITCH_ENCAP_MODE;
1610                } else if (dl_argv_match(dl, "path") &&
1611                           (o_all & DL_OPT_RESOURCE_PATH)) {
1612                        dl_arg_inc(dl);
1613                        err = dl_argv_str(dl, &opts->resource_path);
1614                        if (err)
1615                                return err;
1616                        o_found |= DL_OPT_RESOURCE_PATH;
1617                } else if (dl_argv_match(dl, "size") &&
1618                           (o_all & DL_OPT_RESOURCE_SIZE)) {
1619                        dl_arg_inc(dl);
1620                        err = dl_argv_uint64_t(dl, &opts->resource_size);
1621                        if (err)
1622                                return err;
1623                        o_found |= DL_OPT_RESOURCE_SIZE;
1624                } else if (dl_argv_match(dl, "name") &&
1625                           (o_all & DL_OPT_PARAM_NAME)) {
1626                        dl_arg_inc(dl);
1627                        err = dl_argv_str(dl, &opts->param_name);
1628                        if (err)
1629                                return err;
1630                        o_found |= DL_OPT_PARAM_NAME;
1631                } else if (dl_argv_match(dl, "value") &&
1632                           (o_all & DL_OPT_PARAM_VALUE)) {
1633                        dl_arg_inc(dl);
1634                        err = dl_argv_str(dl, &opts->param_value);
1635                        if (err)
1636                                return err;
1637                        o_found |= DL_OPT_PARAM_VALUE;
1638                } else if (dl_argv_match(dl, "cmode") &&
1639                           (o_all & DL_OPT_PARAM_CMODE)) {
1640                        const char *cmodestr;
1641
1642                        dl_arg_inc(dl);
1643                        err = dl_argv_str(dl, &cmodestr);
1644                        if (err)
1645                                return err;
1646                        err = param_cmode_get(cmodestr, &opts->cmode);
1647                        if (err)
1648                                return err;
1649                        o_found |= DL_OPT_PARAM_CMODE;
1650                } else if (dl_argv_match(dl, "snapshot") &&
1651                           (o_all & DL_OPT_REGION_SNAPSHOT_ID)) {
1652                        dl_arg_inc(dl);
1653                        err = dl_argv_uint32_t(dl, &opts->region_snapshot_id);
1654                        if (err)
1655                                return err;
1656                        o_found |= DL_OPT_REGION_SNAPSHOT_ID;
1657                } else if (dl_argv_match(dl, "address") &&
1658                           (o_all & DL_OPT_REGION_ADDRESS)) {
1659                        dl_arg_inc(dl);
1660                        err = dl_argv_uint64_t(dl, &opts->region_address);
1661                        if (err)
1662                                return err;
1663                        o_found |= DL_OPT_REGION_ADDRESS;
1664                } else if (dl_argv_match(dl, "length") &&
1665                           (o_all & DL_OPT_REGION_LENGTH)) {
1666                        dl_arg_inc(dl);
1667                        err = dl_argv_uint64_t(dl, &opts->region_length);
1668                        if (err)
1669                                return err;
1670                        o_found |= DL_OPT_REGION_LENGTH;
1671                } else if (dl_argv_match(dl, "file") &&
1672                           (o_all & DL_OPT_FLASH_FILE_NAME)) {
1673                        dl_arg_inc(dl);
1674                        err = dl_argv_str(dl, &opts->flash_file_name);
1675                        if (err)
1676                                return err;
1677                        o_found |= DL_OPT_FLASH_FILE_NAME;
1678                } else if (dl_argv_match(dl, "component") &&
1679                           (o_all & DL_OPT_FLASH_COMPONENT)) {
1680                        dl_arg_inc(dl);
1681                        err = dl_argv_str(dl, &opts->flash_component);
1682                        if (err)
1683                                return err;
1684                        o_found |= DL_OPT_FLASH_COMPONENT;
1685
1686                } else if (dl_argv_match(dl, "overwrite") &&
1687                                (o_all & DL_OPT_FLASH_OVERWRITE)) {
1688                        const char *sectionstr;
1689
1690                        dl_arg_inc(dl);
1691                        err = dl_argv_str(dl, &sectionstr);
1692                        if(err)
1693                                return err;
1694                        err = flash_overwrite_section_get(sectionstr,
1695                                                          &opts->overwrite_mask);
1696                        if (err)
1697                                return err;
1698                        o_found |= DL_OPT_FLASH_OVERWRITE;
1699
1700                } else if (dl_argv_match(dl, "reporter") &&
1701                           (o_all & DL_OPT_HEALTH_REPORTER_NAME)) {
1702                        dl_arg_inc(dl);
1703                        err = dl_argv_str(dl, &opts->reporter_name);
1704                        if (err)
1705                                return err;
1706                        o_found |= DL_OPT_HEALTH_REPORTER_NAME;
1707                } else if (dl_argv_match(dl, "grace_period") &&
1708                           (o_all & DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD)) {
1709                        dl_arg_inc(dl);
1710                        err = dl_argv_uint64_t(dl,
1711                                               &opts->reporter_graceful_period);
1712                        if (err)
1713                                return err;
1714                        o_found |= DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD;
1715                } else if (dl_argv_match(dl, "auto_recover") &&
1716                        (o_all & DL_OPT_HEALTH_REPORTER_AUTO_RECOVER)) {
1717                        dl_arg_inc(dl);
1718                        err = dl_argv_bool(dl, &opts->reporter_auto_recover);
1719                        if (err)
1720                                return err;
1721                        o_found |= DL_OPT_HEALTH_REPORTER_AUTO_RECOVER;
1722                } else if (dl_argv_match(dl, "auto_dump") &&
1723                        (o_all & DL_OPT_HEALTH_REPORTER_AUTO_DUMP)) {
1724                        dl_arg_inc(dl);
1725                        err = dl_argv_bool(dl, &opts->reporter_auto_dump);
1726                        if (err)
1727                                return err;
1728                        o_found |= DL_OPT_HEALTH_REPORTER_AUTO_DUMP;
1729                } else if (dl_argv_match(dl, "trap") &&
1730                           (o_all & DL_OPT_TRAP_NAME)) {
1731                        dl_arg_inc(dl);
1732                        err = dl_argv_str(dl, &opts->trap_name);
1733                        if (err)
1734                                return err;
1735                        o_found |= DL_OPT_TRAP_NAME;
1736                } else if (dl_argv_match(dl, "group") &&
1737                           (o_all & DL_OPT_TRAP_GROUP_NAME)) {
1738                        dl_arg_inc(dl);
1739                        err = dl_argv_str(dl, &opts->trap_group_name);
1740                        if (err)
1741                                return err;
1742                        o_found |= DL_OPT_TRAP_GROUP_NAME;
1743                } else if (dl_argv_match(dl, "action") &&
1744                           (o_all & DL_OPT_TRAP_ACTION)) {
1745                        const char *actionstr;
1746
1747                        dl_arg_inc(dl);
1748                        err = dl_argv_str(dl, &actionstr);
1749                        if (err)
1750                                return err;
1751                        err = trap_action_get(actionstr, &opts->trap_action);
1752                        if (err)
1753                                return err;
1754                        o_found |= DL_OPT_TRAP_ACTION;
1755                } else if (dl_argv_match(dl, "netns") &&
1756                        (o_all & DL_OPT_NETNS)) {
1757                        const char *netns_str;
1758
1759                        dl_arg_inc(dl);
1760                        err = dl_argv_str(dl, &netns_str);
1761                        if (err)
1762                                return err;
1763                        opts->netns = netns_get_fd(netns_str);
1764                        if ((int)opts->netns < 0) {
1765                                dl_arg_dec(dl);
1766                                err = dl_argv_uint32_t(dl, &opts->netns);
1767                                if (err)
1768                                        return err;
1769                                opts->netns_is_pid = true;
1770                        }
1771                        o_found |= DL_OPT_NETNS;
1772                } else if (dl_argv_match(dl, "action") &&
1773                           (o_all & DL_OPT_RELOAD_ACTION)) {
1774                        const char *actionstr;
1775
1776                        dl_arg_inc(dl);
1777                        err = dl_argv_str(dl, &actionstr);
1778                        if (err)
1779                                return err;
1780                        err = reload_action_get(dl, actionstr, &opts->reload_action);
1781                        if (err)
1782                                return err;
1783                        o_found |= DL_OPT_RELOAD_ACTION;
1784                } else if (dl_argv_match(dl, "limit") &&
1785                           (o_all & DL_OPT_RELOAD_LIMIT)) {
1786                        const char *limitstr;
1787
1788                        dl_arg_inc(dl);
1789                        err = dl_argv_str(dl, &limitstr);
1790                        if (err)
1791                                return err;
1792                        err = reload_limit_get(dl, limitstr, &opts->reload_limit);
1793                        if (err)
1794                                return err;
1795                        o_found |= DL_OPT_RELOAD_LIMIT;
1796                } else if (dl_argv_match(dl, "policer") &&
1797                           (o_all & DL_OPT_TRAP_POLICER_ID)) {
1798                        dl_arg_inc(dl);
1799                        err = dl_argv_uint32_t(dl, &opts->trap_policer_id);
1800                        if (err)
1801                                return err;
1802                        o_found |= DL_OPT_TRAP_POLICER_ID;
1803                } else if (dl_argv_match(dl, "nopolicer") &&
1804                           (o_all & DL_OPT_TRAP_POLICER_ID)) {
1805                        dl_arg_inc(dl);
1806                        opts->trap_policer_id = 0;
1807                        o_found |= DL_OPT_TRAP_POLICER_ID;
1808                } else if (dl_argv_match(dl, "rate") &&
1809                           (o_all & DL_OPT_TRAP_POLICER_RATE)) {
1810                        dl_arg_inc(dl);
1811                        err = dl_argv_uint64_t(dl, &opts->trap_policer_rate);
1812                        if (err)
1813                                return err;
1814                        o_found |= DL_OPT_TRAP_POLICER_RATE;
1815                } else if (dl_argv_match(dl, "burst") &&
1816                           (o_all & DL_OPT_TRAP_POLICER_BURST)) {
1817                        dl_arg_inc(dl);
1818                        err = dl_argv_uint64_t(dl, &opts->trap_policer_burst);
1819                        if (err)
1820                                return err;
1821                        o_found |= DL_OPT_TRAP_POLICER_BURST;
1822                } else if (dl_argv_match(dl, "hw_addr") &&
1823                           (o_all & DL_OPT_PORT_FUNCTION_HW_ADDR)) {
1824                        const char *addrstr;
1825
1826                        dl_arg_inc(dl);
1827                        err = dl_argv_str(dl, &addrstr);
1828                        if (err)
1829                                return err;
1830                        err = hw_addr_parse(addrstr, opts->port_function_hw_addr,
1831                                            &opts->port_function_hw_addr_len);
1832                        if (err)
1833                                return err;
1834                        o_found |= DL_OPT_PORT_FUNCTION_HW_ADDR;
1835
1836                } else {
1837                        pr_err("Unknown option \"%s\"\n", dl_argv(dl));
1838                        return -EINVAL;
1839                }
1840        }
1841
1842        opts->present = o_found;
1843
1844        if ((o_optional & DL_OPT_SB) && !(o_found & DL_OPT_SB)) {
1845                opts->sb_index = 0;
1846                opts->present |= DL_OPT_SB;
1847        }
1848
1849        return dl_args_finding_required_validate(o_required, o_found);
1850}
1851
1852static void
1853dl_function_attr_put(struct nlmsghdr *nlh, const struct dl_opts *opts)
1854{
1855        struct nlattr *nest;
1856
1857        nest = mnl_attr_nest_start(nlh, DEVLINK_ATTR_PORT_FUNCTION);
1858        mnl_attr_put(nlh, DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR,
1859                     opts->port_function_hw_addr_len,
1860                     opts->port_function_hw_addr);
1861        mnl_attr_nest_end(nlh, nest);
1862}
1863
1864static void
1865dl_flash_update_overwrite_put(struct nlmsghdr *nlh, const struct dl_opts *opts)
1866{
1867        struct nla_bitfield32 overwrite_mask;
1868
1869        overwrite_mask.selector = DEVLINK_SUPPORTED_FLASH_OVERWRITE_SECTIONS;
1870        overwrite_mask.value = opts->overwrite_mask;
1871
1872        mnl_attr_put(nlh, DEVLINK_ATTR_FLASH_UPDATE_OVERWRITE_MASK,
1873                     sizeof(overwrite_mask), &overwrite_mask);
1874}
1875
1876static void
1877dl_reload_limits_put(struct nlmsghdr *nlh, const struct dl_opts *opts)
1878{
1879        struct nla_bitfield32 limits;
1880
1881        limits.selector = DEVLINK_RELOAD_LIMITS_VALID_MASK;
1882        limits.value = BIT(opts->reload_limit);
1883        mnl_attr_put(nlh, DEVLINK_ATTR_RELOAD_LIMITS, sizeof(limits), &limits);
1884}
1885
1886static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl)
1887{
1888        struct dl_opts *opts = &dl->opts;
1889
1890        if (opts->present & DL_OPT_HANDLE) {
1891                mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, opts->bus_name);
1892                mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, opts->dev_name);
1893        } else if (opts->present & DL_OPT_HANDLEP) {
1894                mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, opts->bus_name);
1895                mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, opts->dev_name);
1896                mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX,
1897                                 opts->port_index);
1898        } else if (opts->present & DL_OPT_HANDLE_REGION) {
1899                mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, opts->bus_name);
1900                mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, opts->dev_name);
1901                mnl_attr_put_strz(nlh, DEVLINK_ATTR_REGION_NAME,
1902                                  opts->region_name);
1903        }
1904        if (opts->present & DL_OPT_PORT_TYPE)
1905                mnl_attr_put_u16(nlh, DEVLINK_ATTR_PORT_TYPE,
1906                                 opts->port_type);
1907        if (opts->present & DL_OPT_PORT_COUNT)
1908                mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_SPLIT_COUNT,
1909                                 opts->port_count);
1910        if (opts->present & DL_OPT_SB)
1911                mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX,
1912                                 opts->sb_index);
1913        if (opts->present & DL_OPT_SB_POOL)
1914                mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX,
1915                                 opts->sb_pool_index);
1916        if (opts->present & DL_OPT_SB_SIZE)
1917                mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_POOL_SIZE,
1918                                 opts->sb_pool_size);
1919        if (opts->present & DL_OPT_SB_TYPE)
1920                mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_TYPE,
1921                                opts->sb_pool_type);
1922        if (opts->present & DL_OPT_SB_THTYPE)
1923                mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE,
1924                                opts->sb_pool_thtype);
1925        if (opts->present & DL_OPT_SB_TH)
1926                mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_THRESHOLD,
1927                                 opts->sb_threshold);
1928        if (opts->present & DL_OPT_SB_TC)
1929                mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_TC_INDEX,
1930                                 opts->sb_tc_index);
1931        if (opts->present & DL_OPT_ESWITCH_MODE)
1932                mnl_attr_put_u16(nlh, DEVLINK_ATTR_ESWITCH_MODE,
1933                                 opts->eswitch_mode);
1934        if (opts->present & DL_OPT_ESWITCH_INLINE_MODE)
1935                mnl_attr_put_u8(nlh, DEVLINK_ATTR_ESWITCH_INLINE_MODE,
1936                                opts->eswitch_inline_mode);
1937        if (opts->present & DL_OPT_DPIPE_TABLE_NAME)
1938                mnl_attr_put_strz(nlh, DEVLINK_ATTR_DPIPE_TABLE_NAME,
1939                                  opts->dpipe_table_name);
1940        if (opts->present & DL_OPT_DPIPE_TABLE_COUNTERS)
1941                mnl_attr_put_u8(nlh, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED,
1942                                opts->dpipe_counters_enabled);
1943        if (opts->present & DL_OPT_ESWITCH_ENCAP_MODE)
1944                mnl_attr_put_u8(nlh, DEVLINK_ATTR_ESWITCH_ENCAP_MODE,
1945                                opts->eswitch_encap_mode);
1946        if ((opts->present & DL_OPT_RESOURCE_PATH) && opts->resource_id_valid)
1947                mnl_attr_put_u64(nlh, DEVLINK_ATTR_RESOURCE_ID,
1948                                 opts->resource_id);
1949        if (opts->present & DL_OPT_RESOURCE_SIZE)
1950                mnl_attr_put_u64(nlh, DEVLINK_ATTR_RESOURCE_SIZE,
1951                                 opts->resource_size);
1952        if (opts->present & DL_OPT_PARAM_NAME)
1953                mnl_attr_put_strz(nlh, DEVLINK_ATTR_PARAM_NAME,
1954                                  opts->param_name);
1955        if (opts->present & DL_OPT_PARAM_CMODE)
1956                mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_VALUE_CMODE,
1957                                opts->cmode);
1958        if (opts->present & DL_OPT_REGION_SNAPSHOT_ID)
1959                mnl_attr_put_u32(nlh, DEVLINK_ATTR_REGION_SNAPSHOT_ID,
1960                                 opts->region_snapshot_id);
1961        if (opts->present & DL_OPT_REGION_ADDRESS)
1962                mnl_attr_put_u64(nlh, DEVLINK_ATTR_REGION_CHUNK_ADDR,
1963                                 opts->region_address);
1964        if (opts->present & DL_OPT_REGION_LENGTH)
1965                mnl_attr_put_u64(nlh, DEVLINK_ATTR_REGION_CHUNK_LEN,
1966                                 opts->region_length);
1967        if (opts->present & DL_OPT_FLASH_FILE_NAME)
1968                mnl_attr_put_strz(nlh, DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME,
1969                                  opts->flash_file_name);
1970        if (opts->present & DL_OPT_FLASH_COMPONENT)
1971                mnl_attr_put_strz(nlh, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT,
1972                                  opts->flash_component);
1973        if (opts->present & DL_OPT_FLASH_OVERWRITE)
1974                dl_flash_update_overwrite_put(nlh, opts);
1975        if (opts->present & DL_OPT_HEALTH_REPORTER_NAME)
1976                mnl_attr_put_strz(nlh, DEVLINK_ATTR_HEALTH_REPORTER_NAME,
1977                                  opts->reporter_name);
1978        if (opts->present & DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD)
1979                mnl_attr_put_u64(nlh,
1980                                 DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
1981                                 opts->reporter_graceful_period);
1982        if (opts->present & DL_OPT_HEALTH_REPORTER_AUTO_RECOVER)
1983                mnl_attr_put_u8(nlh, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER,
1984                                opts->reporter_auto_recover);
1985        if (opts->present & DL_OPT_HEALTH_REPORTER_AUTO_DUMP)
1986                mnl_attr_put_u8(nlh, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP,
1987                                opts->reporter_auto_dump);
1988        if (opts->present & DL_OPT_TRAP_NAME)
1989                mnl_attr_put_strz(nlh, DEVLINK_ATTR_TRAP_NAME,
1990                                  opts->trap_name);
1991        if (opts->present & DL_OPT_TRAP_GROUP_NAME)
1992                mnl_attr_put_strz(nlh, DEVLINK_ATTR_TRAP_GROUP_NAME,
1993                                  opts->trap_group_name);
1994        if (opts->present & DL_OPT_TRAP_ACTION)
1995                mnl_attr_put_u8(nlh, DEVLINK_ATTR_TRAP_ACTION,
1996                                opts->trap_action);
1997        if (opts->present & DL_OPT_NETNS)
1998                mnl_attr_put_u32(nlh,
1999                                 opts->netns_is_pid ? DEVLINK_ATTR_NETNS_PID :
2000                                                      DEVLINK_ATTR_NETNS_FD,
2001                                 opts->netns);
2002        if (opts->present & DL_OPT_RELOAD_ACTION)
2003                mnl_attr_put_u8(nlh, DEVLINK_ATTR_RELOAD_ACTION,
2004                                opts->reload_action);
2005        if (opts->present & DL_OPT_RELOAD_LIMIT)
2006                dl_reload_limits_put(nlh, opts);
2007        if (opts->present & DL_OPT_TRAP_POLICER_ID)
2008                mnl_attr_put_u32(nlh, DEVLINK_ATTR_TRAP_POLICER_ID,
2009                                 opts->trap_policer_id);
2010        if (opts->present & DL_OPT_TRAP_POLICER_RATE)
2011                mnl_attr_put_u64(nlh, DEVLINK_ATTR_TRAP_POLICER_RATE,
2012                                 opts->trap_policer_rate);
2013        if (opts->present & DL_OPT_TRAP_POLICER_BURST)
2014                mnl_attr_put_u64(nlh, DEVLINK_ATTR_TRAP_POLICER_BURST,
2015                                 opts->trap_policer_burst);
2016        if (opts->present & DL_OPT_PORT_FUNCTION_HW_ADDR)
2017                dl_function_attr_put(nlh, opts);
2018}
2019
2020static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl,
2021                             uint64_t o_required, uint64_t o_optional)
2022{
2023        int err;
2024
2025        err = dl_argv_parse(dl, o_required, o_optional);
2026        if (err)
2027                return err;
2028        dl_opts_put(nlh, dl);
2029        return 0;
2030}
2031
2032static bool dl_dump_filter(struct dl *dl, struct nlattr **tb)
2033{
2034        struct dl_opts *opts = &dl->opts;
2035        struct nlattr *attr_bus_name = tb[DEVLINK_ATTR_BUS_NAME];
2036        struct nlattr *attr_dev_name = tb[DEVLINK_ATTR_DEV_NAME];
2037        struct nlattr *attr_port_index = tb[DEVLINK_ATTR_PORT_INDEX];
2038        struct nlattr *attr_sb_index = tb[DEVLINK_ATTR_SB_INDEX];
2039
2040        if (opts->present & DL_OPT_HANDLE &&
2041            attr_bus_name && attr_dev_name) {
2042                const char *bus_name = mnl_attr_get_str(attr_bus_name);
2043                const char *dev_name = mnl_attr_get_str(attr_dev_name);
2044
2045                if (strcmp(bus_name, opts->bus_name) != 0 ||
2046                    strcmp(dev_name, opts->dev_name) != 0)
2047                        return false;
2048        }
2049        if (opts->present & DL_OPT_HANDLEP &&
2050            attr_bus_name && attr_dev_name && attr_port_index) {
2051                const char *bus_name = mnl_attr_get_str(attr_bus_name);
2052                const char *dev_name = mnl_attr_get_str(attr_dev_name);
2053                uint32_t port_index = mnl_attr_get_u32(attr_port_index);
2054
2055                if (strcmp(bus_name, opts->bus_name) != 0 ||
2056                    strcmp(dev_name, opts->dev_name) != 0 ||
2057                    port_index != opts->port_index)
2058                        return false;
2059        }
2060        if (opts->present & DL_OPT_SB && attr_sb_index) {
2061                uint32_t sb_index = mnl_attr_get_u32(attr_sb_index);
2062
2063                if (sb_index != opts->sb_index)
2064                        return false;
2065        }
2066        return true;
2067}
2068
2069static void cmd_dev_help(void)
2070{
2071        pr_err("Usage: devlink dev show [ DEV ]\n");
2072        pr_err("       devlink dev eswitch set DEV [ mode { legacy | switchdev } ]\n");
2073        pr_err("                               [ inline-mode { none | link | network | transport } ]\n");
2074        pr_err("                               [ encap-mode { none | basic } ]\n");
2075        pr_err("       devlink dev eswitch show DEV\n");
2076        pr_err("       devlink dev param set DEV name PARAMETER value VALUE cmode { permanent | driverinit | runtime }\n");
2077        pr_err("       devlink dev param show [DEV name PARAMETER]\n");
2078        pr_err("       devlink dev reload DEV [ netns { PID | NAME | ID } ]\n");
2079        pr_err("                              [ action { driver_reinit | fw_activate } ] [ limit no_reset ]\n");
2080        pr_err("       devlink dev info [ DEV ]\n");
2081        pr_err("       devlink dev flash DEV file PATH [ component NAME ] [ overwrite SECTION ]\n");
2082}
2083
2084static bool cmp_arr_last_handle(struct dl *dl, const char *bus_name,
2085                                const char *dev_name)
2086{
2087        if (!dl->arr_last.present)
2088                return false;
2089        return strcmp(dl->arr_last.bus_name, bus_name) == 0 &&
2090               strcmp(dl->arr_last.dev_name, dev_name) == 0;
2091}
2092
2093static void arr_last_handle_set(struct dl *dl, const char *bus_name,
2094                                const char *dev_name)
2095{
2096        dl->arr_last.present = true;
2097        free(dl->arr_last.dev_name);
2098        free(dl->arr_last.bus_name);
2099        dl->arr_last.bus_name = strdup(bus_name);
2100        dl->arr_last.dev_name = strdup(dev_name);
2101}
2102
2103static bool should_arr_last_handle_start(struct dl *dl, const char *bus_name,
2104                                         const char *dev_name)
2105{
2106        return !cmp_arr_last_handle(dl, bus_name, dev_name);
2107}
2108
2109static bool should_arr_last_handle_end(struct dl *dl, const char *bus_name,
2110                                       const char *dev_name)
2111{
2112        return dl->arr_last.present &&
2113               !cmp_arr_last_handle(dl, bus_name, dev_name);
2114}
2115
2116static void __pr_out_handle_start(struct dl *dl, struct nlattr **tb,
2117                                  bool content, bool array)
2118{
2119        const char *bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
2120        const char *dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
2121        char buf[64];
2122
2123        sprintf(buf, "%s/%s", bus_name, dev_name);
2124
2125        if (dl->json_output) {
2126                if (array) {
2127                        if (should_arr_last_handle_end(dl, bus_name, dev_name))
2128                                close_json_array(PRINT_JSON, NULL);
2129                        if (should_arr_last_handle_start(dl, bus_name,
2130                                                         dev_name)) {
2131                                open_json_array(PRINT_JSON, buf);
2132                                open_json_object(NULL);
2133                                arr_last_handle_set(dl, bus_name, dev_name);
2134                        } else {
2135                                open_json_object(NULL);
2136                        }
2137                } else {
2138                        open_json_object(buf);
2139                }
2140        } else {
2141                if (array) {
2142                        if (should_arr_last_handle_end(dl, bus_name, dev_name))
2143                                __pr_out_indent_dec();
2144                        if (should_arr_last_handle_start(dl, bus_name,
2145                                                         dev_name)) {
2146                                pr_out("%s%s", buf, content ? ":" : "");
2147                                __pr_out_newline();
2148                                __pr_out_indent_inc();
2149                                arr_last_handle_set(dl, bus_name, dev_name);
2150                        }
2151                } else {
2152                        pr_out("%s%s", buf, content ? ":" : "");
2153                }
2154        }
2155}
2156
2157static void pr_out_handle_start_arr(struct dl *dl, struct nlattr **tb)
2158{
2159        __pr_out_handle_start(dl, tb, true, true);
2160}
2161
2162static void pr_out_handle_end(struct dl *dl)
2163{
2164        if (dl->json_output)
2165                close_json_object();
2166        else
2167                __pr_out_newline();
2168}
2169
2170static void pr_out_handle(struct dl *dl, struct nlattr **tb)
2171{
2172        __pr_out_handle_start(dl, tb, false, false);
2173        pr_out_handle_end(dl);
2174}
2175
2176static bool cmp_arr_last_port_handle(struct dl *dl, const char *bus_name,
2177                                     const char *dev_name, uint32_t port_index)
2178{
2179        return cmp_arr_last_handle(dl, bus_name, dev_name) &&
2180               dl->arr_last.port_index == port_index;
2181}
2182
2183static void arr_last_port_handle_set(struct dl *dl, const char *bus_name,
2184                                     const char *dev_name, uint32_t port_index)
2185{
2186        arr_last_handle_set(dl, bus_name, dev_name);
2187        dl->arr_last.port_index = port_index;
2188}
2189
2190static bool should_arr_last_port_handle_start(struct dl *dl,
2191                                              const char *bus_name,
2192                                              const char *dev_name,
2193                                              uint32_t port_index)
2194{
2195        return !cmp_arr_last_port_handle(dl, bus_name, dev_name, port_index);
2196}
2197
2198static bool should_arr_last_port_handle_end(struct dl *dl,
2199                                            const char *bus_name,
2200                                            const char *dev_name,
2201                                            uint32_t port_index)
2202{
2203        return dl->arr_last.present &&
2204               !cmp_arr_last_port_handle(dl, bus_name, dev_name, port_index);
2205}
2206
2207static void __pr_out_port_handle_start(struct dl *dl, const char *bus_name,
2208                                       const char *dev_name,
2209                                       uint32_t port_index, bool try_nice,
2210                                       bool array)
2211{
2212        static char buf[64];
2213        char *ifname = NULL;
2214
2215        if (dl->no_nice_names || !try_nice ||
2216            ifname_map_rev_lookup(dl, bus_name, dev_name,
2217                                  port_index, &ifname) != 0)
2218                sprintf(buf, "%s/%s/%d", bus_name, dev_name, port_index);
2219        else
2220                sprintf(buf, "%s", ifname);
2221
2222        if (dl->json_output) {
2223                if (array) {
2224                        if (should_arr_last_port_handle_end(dl, bus_name,
2225                                                            dev_name,
2226                                                            port_index))
2227                                close_json_array(PRINT_JSON, NULL);
2228                        if (should_arr_last_port_handle_start(dl, bus_name,
2229                                                              dev_name,
2230                                                              port_index)) {
2231                                open_json_array(PRINT_JSON, buf);
2232                                open_json_object(NULL);
2233                                arr_last_port_handle_set(dl, bus_name, dev_name,
2234                                                         port_index);
2235                        } else {
2236                                open_json_object(NULL);
2237                        }
2238                } else {
2239                        open_json_object(buf);
2240                }
2241        } else {
2242                if (array) {
2243                        if (should_arr_last_port_handle_end(dl, bus_name, dev_name, port_index))
2244                                __pr_out_indent_dec();
2245                        if (should_arr_last_port_handle_start(dl, bus_name,
2246                                                              dev_name, port_index)) {
2247                                pr_out("%s:", buf);
2248                                __pr_out_newline();
2249                                __pr_out_indent_inc();
2250                                arr_last_port_handle_set(dl, bus_name, dev_name, port_index);
2251                        }
2252                } else {
2253                        pr_out("%s:", buf);
2254                }
2255        }
2256}
2257
2258static void pr_out_port_handle_start(struct dl *dl, struct nlattr **tb, bool try_nice)
2259{
2260        const char *bus_name;
2261        const char *dev_name;
2262        uint32_t port_index;
2263
2264        bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
2265        dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
2266        port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]);
2267        __pr_out_port_handle_start(dl, bus_name, dev_name, port_index, try_nice, false);
2268}
2269
2270static void pr_out_port_handle_start_arr(struct dl *dl, struct nlattr **tb, bool try_nice)
2271{
2272        const char *bus_name;
2273        const char *dev_name;
2274        uint32_t port_index;
2275
2276        bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
2277        dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
2278        port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]);
2279        __pr_out_port_handle_start(dl, bus_name, dev_name, port_index, try_nice, true);
2280}
2281
2282static void pr_out_port_handle_end(struct dl *dl)
2283{
2284        if (dl->json_output)
2285                close_json_object();
2286        else
2287                pr_out("\n");
2288}
2289
2290static void pr_out_region_chunk_start(struct dl *dl, uint64_t addr)
2291{
2292        if (dl->json_output) {
2293                print_uint(PRINT_JSON, "address", NULL, addr);
2294                open_json_array(PRINT_JSON, "data");
2295        }
2296}
2297
2298static void pr_out_region_chunk_end(struct dl *dl)
2299{
2300        if (dl->json_output)
2301                close_json_array(PRINT_JSON, NULL);
2302}
2303
2304static void pr_out_region_chunk(struct dl *dl, uint8_t *data, uint32_t len,
2305                                uint64_t addr)
2306{
2307        static uint64_t align_val;
2308        uint32_t i = 0;
2309
2310        pr_out_region_chunk_start(dl, addr);
2311        while (i < len) {
2312                if (!dl->json_output)
2313                        if (!(align_val % 16))
2314                                pr_out("%s%016"PRIx64" ",
2315                                       align_val ? "\n" : "",
2316                                       addr);
2317
2318                align_val++;
2319
2320                if (dl->json_output)
2321                        print_int(PRINT_JSON, NULL, NULL, data[i]);
2322                else
2323                        pr_out("%02x ", data[i]);
2324
2325                addr++;
2326                i++;
2327        }
2328        pr_out_region_chunk_end(dl);
2329}
2330
2331static void pr_out_stats(struct dl *dl, struct nlattr *nla_stats)
2332{
2333        struct nlattr *tb[DEVLINK_ATTR_STATS_MAX + 1] = {};
2334        int err;
2335
2336        if (!dl->stats)
2337                return;
2338
2339        err = mnl_attr_parse_nested(nla_stats, attr_stats_cb, tb);
2340        if (err != MNL_CB_OK)
2341                return;
2342
2343        pr_out_object_start(dl, "stats");
2344        pr_out_object_start(dl, "rx");
2345        if (tb[DEVLINK_ATTR_STATS_RX_BYTES])
2346                pr_out_u64(dl, "bytes",
2347                           mnl_attr_get_u64(tb[DEVLINK_ATTR_STATS_RX_BYTES]));
2348        if (tb[DEVLINK_ATTR_STATS_RX_PACKETS])
2349                pr_out_u64(dl, "packets",
2350                           mnl_attr_get_u64(tb[DEVLINK_ATTR_STATS_RX_PACKETS]));
2351        if (tb[DEVLINK_ATTR_STATS_RX_DROPPED])
2352                pr_out_u64(dl, "dropped",
2353                           mnl_attr_get_u64(tb[DEVLINK_ATTR_STATS_RX_DROPPED]));
2354        pr_out_object_end(dl);
2355        pr_out_object_end(dl);
2356}
2357
2358static const char *param_cmode_name(uint8_t cmode)
2359{
2360        switch (cmode) {
2361        case DEVLINK_PARAM_CMODE_RUNTIME:
2362                return PARAM_CMODE_RUNTIME_STR;
2363        case DEVLINK_PARAM_CMODE_DRIVERINIT:
2364                return PARAM_CMODE_DRIVERINIT_STR;
2365        case DEVLINK_PARAM_CMODE_PERMANENT:
2366                return PARAM_CMODE_PERMANENT_STR;
2367        default: return "<unknown type>";
2368        }
2369}
2370
2371static const char *reload_action_name(uint8_t reload_action)
2372{
2373        switch (reload_action) {
2374        case DEVLINK_RELOAD_ACTION_DRIVER_REINIT:
2375                return "driver_reinit";
2376        case DEVLINK_RELOAD_ACTION_FW_ACTIVATE:
2377                return "fw_activate";
2378        default:
2379                return "<unknown reload action>";
2380        }
2381}
2382
2383static const char *reload_limit_name(uint8_t reload_limit)
2384{
2385        switch (reload_limit) {
2386        case DEVLINK_RELOAD_LIMIT_UNSPEC:
2387                return "unspecified";
2388        case DEVLINK_RELOAD_LIMIT_NO_RESET:
2389                return "no_reset";
2390        default:
2391                return "<unknown reload action>";
2392        }
2393}
2394
2395static const char *eswitch_mode_name(uint32_t mode)
2396{
2397        switch (mode) {
2398        case DEVLINK_ESWITCH_MODE_LEGACY: return ESWITCH_MODE_LEGACY;
2399        case DEVLINK_ESWITCH_MODE_SWITCHDEV: return ESWITCH_MODE_SWITCHDEV;
2400        default: return "<unknown mode>";
2401        }
2402}
2403
2404static const char *eswitch_inline_mode_name(uint32_t mode)
2405{
2406        switch (mode) {
2407        case DEVLINK_ESWITCH_INLINE_MODE_NONE:
2408                return ESWITCH_INLINE_MODE_NONE;
2409        case DEVLINK_ESWITCH_INLINE_MODE_LINK:
2410                return ESWITCH_INLINE_MODE_LINK;
2411        case DEVLINK_ESWITCH_INLINE_MODE_NETWORK:
2412                return ESWITCH_INLINE_MODE_NETWORK;
2413        case DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT:
2414                return ESWITCH_INLINE_MODE_TRANSPORT;
2415        default:
2416                return "<unknown mode>";
2417        }
2418}
2419
2420static const char *eswitch_encap_mode_name(uint32_t mode)
2421{
2422        switch (mode) {
2423        case DEVLINK_ESWITCH_ENCAP_MODE_NONE:
2424                return ESWITCH_ENCAP_MODE_NONE;
2425        case DEVLINK_ESWITCH_ENCAP_MODE_BASIC:
2426                return ESWITCH_ENCAP_MODE_BASIC;
2427        default:
2428                return "<unknown mode>";
2429        }
2430}
2431
2432static void pr_out_eswitch(struct dl *dl, struct nlattr **tb)
2433{
2434        __pr_out_handle_start(dl, tb, true, false);
2435
2436        if (tb[DEVLINK_ATTR_ESWITCH_MODE]) {
2437                check_indent_newline(dl);
2438                print_string(PRINT_ANY, "mode", "mode %s",
2439                             eswitch_mode_name(mnl_attr_get_u16(
2440                                     tb[DEVLINK_ATTR_ESWITCH_MODE])));
2441        }
2442        if (tb[DEVLINK_ATTR_ESWITCH_INLINE_MODE]) {
2443                check_indent_newline(dl);
2444                print_string(PRINT_ANY, "inline-mode", "inline-mode %s",
2445                             eswitch_inline_mode_name(mnl_attr_get_u8(
2446                                     tb[DEVLINK_ATTR_ESWITCH_INLINE_MODE])));
2447        }
2448        if (tb[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]) {
2449                check_indent_newline(dl);
2450                print_string(PRINT_ANY, "encap-mode", "encap-mode %s",
2451                             eswitch_encap_mode_name(mnl_attr_get_u8(
2452                                    tb[DEVLINK_ATTR_ESWITCH_ENCAP_MODE])));
2453        }
2454
2455        pr_out_handle_end(dl);
2456}
2457
2458static int cmd_dev_eswitch_show_cb(const struct nlmsghdr *nlh, void *data)
2459{
2460        struct dl *dl = data;
2461        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2462        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
2463
2464        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2465        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
2466                return MNL_CB_ERROR;
2467        pr_out_eswitch(dl, tb);
2468        return MNL_CB_OK;
2469}
2470
2471static int cmd_dev_eswitch_show(struct dl *dl)
2472{
2473        struct nlmsghdr *nlh;
2474        int err;
2475
2476        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_ESWITCH_GET,
2477                               NLM_F_REQUEST | NLM_F_ACK);
2478
2479        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
2480        if (err)
2481                return err;
2482
2483        pr_out_section_start(dl, "dev");
2484        err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_eswitch_show_cb, dl);
2485        pr_out_section_end(dl);
2486        return err;
2487}
2488
2489static int cmd_dev_eswitch_set(struct dl *dl)
2490{
2491        struct nlmsghdr *nlh;
2492        int err;
2493
2494        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_ESWITCH_SET,
2495                               NLM_F_REQUEST | NLM_F_ACK);
2496
2497        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE,
2498                                DL_OPT_ESWITCH_MODE |
2499                                DL_OPT_ESWITCH_INLINE_MODE |
2500                                DL_OPT_ESWITCH_ENCAP_MODE);
2501
2502        if (err)
2503                return err;
2504
2505        if (dl->opts.present == 1) {
2506                pr_err("Need to set at least one option\n");
2507                return -ENOENT;
2508        }
2509
2510        return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
2511}
2512
2513static int cmd_dev_eswitch(struct dl *dl)
2514{
2515        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
2516                cmd_dev_help();
2517                return 0;
2518        } else if (dl_argv_match(dl, "set")) {
2519                dl_arg_inc(dl);
2520                return cmd_dev_eswitch_set(dl);
2521        } else if (dl_argv_match(dl, "show")) {
2522                dl_arg_inc(dl);
2523                return cmd_dev_eswitch_show(dl);
2524        }
2525        pr_err("Command \"%s\" not found\n", dl_argv(dl));
2526        return -ENOENT;
2527}
2528
2529struct param_val_conv {
2530        const char *name;
2531        const char *vstr;
2532        uint32_t vuint;
2533};
2534
2535static bool param_val_conv_exists(const struct param_val_conv *param_val_conv,
2536                                  uint32_t len, const char *name)
2537{
2538        uint32_t i;
2539
2540        for (i = 0; i < len; i++)
2541                if (!strcmp(param_val_conv[i].name, name))
2542                        return true;
2543
2544        return false;
2545}
2546
2547static int
2548param_val_conv_uint_get(const struct param_val_conv *param_val_conv,
2549                        uint32_t len, const char *name, const char *vstr,
2550                        uint32_t *vuint)
2551{
2552        uint32_t i;
2553
2554        for (i = 0; i < len; i++)
2555                if (!strcmp(param_val_conv[i].name, name) &&
2556                    !strcmp(param_val_conv[i].vstr, vstr)) {
2557                        *vuint = param_val_conv[i].vuint;
2558                        return 0;
2559                }
2560
2561        return -ENOENT;
2562}
2563
2564static int
2565param_val_conv_str_get(const struct param_val_conv *param_val_conv,
2566                       uint32_t len, const char *name, uint32_t vuint,
2567                       const char **vstr)
2568{
2569        uint32_t i;
2570
2571        for (i = 0; i < len; i++)
2572                if (!strcmp(param_val_conv[i].name, name) &&
2573                    param_val_conv[i].vuint == vuint) {
2574                        *vstr = param_val_conv[i].vstr;
2575                        return 0;
2576                }
2577
2578        return -ENOENT;
2579}
2580
2581static const struct param_val_conv param_val_conv[] = {
2582        {
2583                .name = "fw_load_policy",
2584                .vstr = "driver",
2585                .vuint = DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DRIVER,
2586        },
2587        {
2588                .name = "fw_load_policy",
2589                .vstr = "flash",
2590                .vuint = DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH,
2591        },
2592        {
2593                .name = "fw_load_policy",
2594                .vstr = "disk",
2595                .vuint = DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DISK,
2596        },
2597        {
2598                .name = "reset_dev_on_drv_probe",
2599                .vstr = "unknown",
2600                .vuint = DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_UNKNOWN,
2601        },
2602        {
2603                .name = "fw_load_policy",
2604                .vstr = "unknown",
2605                .vuint = DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_UNKNOWN,
2606        },
2607        {
2608                .name = "reset_dev_on_drv_probe",
2609                .vstr = "always",
2610                .vuint = DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_ALWAYS,
2611        },
2612        {
2613                .name = "reset_dev_on_drv_probe",
2614                .vstr = "never",
2615                .vuint = DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_NEVER,
2616        },
2617        {
2618                .name = "reset_dev_on_drv_probe",
2619                .vstr = "disk",
2620                .vuint = DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_DISK,
2621        },
2622};
2623
2624#define PARAM_VAL_CONV_LEN ARRAY_SIZE(param_val_conv)
2625
2626static void pr_out_param_value(struct dl *dl, const char *nla_name,
2627                               int nla_type, struct nlattr *nl)
2628{
2629        struct nlattr *nla_value[DEVLINK_ATTR_MAX + 1] = {};
2630        struct nlattr *val_attr;
2631        const char *vstr;
2632        bool conv_exists;
2633        int err;
2634
2635        err = mnl_attr_parse_nested(nl, attr_cb, nla_value);
2636        if (err != MNL_CB_OK)
2637                return;
2638
2639        if (!nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE] ||
2640            (nla_type != MNL_TYPE_FLAG &&
2641             !nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA]))
2642                return;
2643
2644        check_indent_newline(dl);
2645        print_string(PRINT_ANY, "cmode", "cmode %s",
2646                     param_cmode_name(mnl_attr_get_u8(nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE])));
2647
2648        val_attr = nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA];
2649
2650        conv_exists = param_val_conv_exists(param_val_conv, PARAM_VAL_CONV_LEN,
2651                                            nla_name);
2652
2653        switch (nla_type) {
2654        case MNL_TYPE_U8:
2655                if (conv_exists) {
2656                        err = param_val_conv_str_get(param_val_conv,
2657                                                     PARAM_VAL_CONV_LEN,
2658                                                     nla_name,
2659                                                     mnl_attr_get_u8(val_attr),
2660                                                     &vstr);
2661                        if (err)
2662                                return;
2663                        print_string(PRINT_ANY, "value", " value %s", vstr);
2664                } else {
2665                        print_uint(PRINT_ANY, "value", " value %u",
2666                                   mnl_attr_get_u8(val_attr));
2667                }
2668                break;
2669        case MNL_TYPE_U16:
2670                if (conv_exists) {
2671                        err = param_val_conv_str_get(param_val_conv,
2672                                                     PARAM_VAL_CONV_LEN,
2673                                                     nla_name,
2674                                                     mnl_attr_get_u16(val_attr),
2675                                                     &vstr);
2676                        if (err)
2677                                return;
2678                        print_string(PRINT_ANY, "value", " value %s", vstr);
2679                } else {
2680                        print_uint(PRINT_ANY, "value", " value %u",
2681                                   mnl_attr_get_u16(val_attr));
2682                }
2683                break;
2684        case MNL_TYPE_U32:
2685                if (conv_exists) {
2686                        err = param_val_conv_str_get(param_val_conv,
2687                                                     PARAM_VAL_CONV_LEN,
2688                                                     nla_name,
2689                                                     mnl_attr_get_u32(val_attr),
2690                                                     &vstr);
2691                        if (err)
2692                                return;
2693                        print_string(PRINT_ANY, "value", " value %s", vstr);
2694                } else {
2695                        print_uint(PRINT_ANY, "value", " value %u",
2696                                   mnl_attr_get_u32(val_attr));
2697                }
2698                break;
2699        case MNL_TYPE_STRING:
2700                print_string(PRINT_ANY, "value", " value %s",
2701                             mnl_attr_get_str(val_attr));
2702                break;
2703        case MNL_TYPE_FLAG:
2704                print_bool(PRINT_ANY, "value", " value %s", val_attr);
2705                break;
2706        }
2707}
2708
2709static void pr_out_param(struct dl *dl, struct nlattr **tb, bool array)
2710{
2711        struct nlattr *nla_param[DEVLINK_ATTR_MAX + 1] = {};
2712        struct nlattr *param_value_attr;
2713        const char *nla_name;
2714        int nla_type;
2715        int err;
2716
2717        err = mnl_attr_parse_nested(tb[DEVLINK_ATTR_PARAM], attr_cb, nla_param);
2718        if (err != MNL_CB_OK)
2719                return;
2720        if (!nla_param[DEVLINK_ATTR_PARAM_NAME] ||
2721            !nla_param[DEVLINK_ATTR_PARAM_TYPE] ||
2722            !nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST])
2723                return;
2724
2725        if (array)
2726                pr_out_handle_start_arr(dl, tb);
2727        else
2728                __pr_out_handle_start(dl, tb, true, false);
2729
2730        nla_type = mnl_attr_get_u8(nla_param[DEVLINK_ATTR_PARAM_TYPE]);
2731
2732        nla_name = mnl_attr_get_str(nla_param[DEVLINK_ATTR_PARAM_NAME]);
2733        check_indent_newline(dl);
2734        print_string(PRINT_ANY, "name", "name %s ", nla_name);
2735        if (!nla_param[DEVLINK_ATTR_PARAM_GENERIC])
2736                print_string(PRINT_ANY, "type", "type %s", "driver-specific");
2737        else
2738                print_string(PRINT_ANY, "type", "type %s", "generic");
2739
2740        pr_out_array_start(dl, "values");
2741        mnl_attr_for_each_nested(param_value_attr,
2742                                 nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST]) {
2743                pr_out_entry_start(dl);
2744                pr_out_param_value(dl, nla_name, nla_type, param_value_attr);
2745                pr_out_entry_end(dl);
2746        }
2747        pr_out_array_end(dl);
2748        pr_out_handle_end(dl);
2749}
2750
2751static int cmd_dev_param_show_cb(const struct nlmsghdr *nlh, void *data)
2752{
2753        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
2754        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2755        struct dl *dl = data;
2756
2757        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2758        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
2759            !tb[DEVLINK_ATTR_PARAM])
2760                return MNL_CB_ERROR;
2761        pr_out_param(dl, tb, true);
2762        return MNL_CB_OK;
2763}
2764
2765struct param_ctx {
2766        struct dl *dl;
2767        int nla_type;
2768        union {
2769                uint8_t vu8;
2770                uint16_t vu16;
2771                uint32_t vu32;
2772                const char *vstr;
2773                bool vbool;
2774        } value;
2775};
2776
2777static int cmd_dev_param_set_cb(const struct nlmsghdr *nlh, void *data)
2778{
2779        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
2780        struct nlattr *nla_param[DEVLINK_ATTR_MAX + 1] = {};
2781        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2782        struct nlattr *param_value_attr;
2783        enum devlink_param_cmode cmode;
2784        struct param_ctx *ctx = data;
2785        struct dl *dl = ctx->dl;
2786        int nla_type;
2787        int err;
2788
2789        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2790        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
2791            !tb[DEVLINK_ATTR_PARAM])
2792                return MNL_CB_ERROR;
2793
2794        err = mnl_attr_parse_nested(tb[DEVLINK_ATTR_PARAM], attr_cb, nla_param);
2795        if (err != MNL_CB_OK)
2796                return MNL_CB_ERROR;
2797
2798        if (!nla_param[DEVLINK_ATTR_PARAM_TYPE] ||
2799            !nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST])
2800                return MNL_CB_ERROR;
2801
2802        nla_type = mnl_attr_get_u8(nla_param[DEVLINK_ATTR_PARAM_TYPE]);
2803        mnl_attr_for_each_nested(param_value_attr,
2804                                 nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST]) {
2805                struct nlattr *nla_value[DEVLINK_ATTR_MAX + 1] = {};
2806                struct nlattr *val_attr;
2807
2808                err = mnl_attr_parse_nested(param_value_attr,
2809                                            attr_cb, nla_value);
2810                if (err != MNL_CB_OK)
2811                        return MNL_CB_ERROR;
2812
2813                if (!nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE] ||
2814                    (nla_type != MNL_TYPE_FLAG &&
2815                     !nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA]))
2816                        return MNL_CB_ERROR;
2817
2818                cmode = mnl_attr_get_u8(nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
2819                if (cmode == dl->opts.cmode) {
2820                        val_attr = nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA];
2821                        switch (nla_type) {
2822                        case MNL_TYPE_U8:
2823                                ctx->value.vu8 = mnl_attr_get_u8(val_attr);
2824                                break;
2825                        case MNL_TYPE_U16:
2826                                ctx->value.vu16 = mnl_attr_get_u16(val_attr);
2827                                break;
2828                        case MNL_TYPE_U32:
2829                                ctx->value.vu32 = mnl_attr_get_u32(val_attr);
2830                                break;
2831                        case MNL_TYPE_STRING:
2832                                ctx->value.vstr = mnl_attr_get_str(val_attr);
2833                                break;
2834                        case MNL_TYPE_FLAG:
2835                                ctx->value.vbool = val_attr ? true : false;
2836                                break;
2837                        }
2838                        break;
2839                }
2840        }
2841        ctx->nla_type = nla_type;
2842        return MNL_CB_OK;
2843}
2844
2845static int cmd_dev_param_set(struct dl *dl)
2846{
2847        struct param_ctx ctx = {};
2848        struct nlmsghdr *nlh;
2849        bool conv_exists;
2850        uint32_t val_u32 = 0;
2851        uint16_t val_u16;
2852        uint8_t val_u8;
2853        bool val_bool;
2854        int err;
2855
2856        err = dl_argv_parse(dl, DL_OPT_HANDLE |
2857                            DL_OPT_PARAM_NAME |
2858                            DL_OPT_PARAM_VALUE |
2859                            DL_OPT_PARAM_CMODE, 0);
2860        if (err)
2861                return err;
2862
2863        /* Get value type */
2864        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PARAM_GET,
2865                               NLM_F_REQUEST | NLM_F_ACK);
2866        dl_opts_put(nlh, dl);
2867
2868        ctx.dl = dl;
2869        err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_param_set_cb, &ctx);
2870        if (err)
2871                return err;
2872
2873        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PARAM_SET,
2874                               NLM_F_REQUEST | NLM_F_ACK);
2875        dl_opts_put(nlh, dl);
2876
2877        conv_exists = param_val_conv_exists(param_val_conv, PARAM_VAL_CONV_LEN,
2878                                            dl->opts.param_name);
2879
2880        mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_TYPE, ctx.nla_type);
2881        switch (ctx.nla_type) {
2882        case MNL_TYPE_U8:
2883                if (conv_exists) {
2884                        err = param_val_conv_uint_get(param_val_conv,
2885                                                      PARAM_VAL_CONV_LEN,
2886                                                      dl->opts.param_name,
2887                                                      dl->opts.param_value,
2888                                                      &val_u32);
2889                        val_u8 = val_u32;
2890                } else {
2891                        err = strtouint8_t(dl->opts.param_value, &val_u8);
2892                }
2893                if (err)
2894                        goto err_param_value_parse;
2895                if (val_u8 == ctx.value.vu8)
2896                        return 0;
2897                mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u8);
2898                break;
2899        case MNL_TYPE_U16:
2900                if (conv_exists) {
2901                        err = param_val_conv_uint_get(param_val_conv,
2902                                                      PARAM_VAL_CONV_LEN,
2903                                                      dl->opts.param_name,
2904                                                      dl->opts.param_value,
2905                                                      &val_u32);
2906                        val_u16 = val_u32;
2907                } else {
2908                        err = strtouint16_t(dl->opts.param_value, &val_u16);
2909                }
2910                if (err)
2911                        goto err_param_value_parse;
2912                if (val_u16 == ctx.value.vu16)
2913                        return 0;
2914                mnl_attr_put_u16(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u16);
2915                break;
2916        case MNL_TYPE_U32:
2917                if (conv_exists)
2918                        err = param_val_conv_uint_get(param_val_conv,
2919                                                      PARAM_VAL_CONV_LEN,
2920                                                      dl->opts.param_name,
2921                                                      dl->opts.param_value,
2922                                                      &val_u32);
2923                else
2924                        err = strtouint32_t(dl->opts.param_value, &val_u32);
2925                if (err)
2926                        goto err_param_value_parse;
2927                if (val_u32 == ctx.value.vu32)
2928                        return 0;
2929                mnl_attr_put_u32(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u32);
2930                break;
2931        case MNL_TYPE_FLAG:
2932                err = strtobool(dl->opts.param_value, &val_bool);
2933                if (err)
2934                        goto err_param_value_parse;
2935                if (val_bool == ctx.value.vbool)
2936                        return 0;
2937                if (val_bool)
2938                        mnl_attr_put(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA,
2939                                     0, NULL);
2940                break;
2941        case MNL_TYPE_STRING:
2942                mnl_attr_put_strz(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA,
2943                                  dl->opts.param_value);
2944                if (!strcmp(dl->opts.param_value, ctx.value.vstr))
2945                        return 0;
2946                break;
2947        default:
2948                printf("Value type not supported\n");
2949                return -ENOTSUP;
2950        }
2951        return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
2952
2953err_param_value_parse:
2954        pr_err("Value \"%s\" is not a number or not within range\n",
2955               dl->opts.param_value);
2956        return err;
2957}
2958
2959static int cmd_dev_param_show(struct dl *dl)
2960{
2961        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
2962        struct nlmsghdr *nlh;
2963        int err;
2964
2965        if (dl_argc(dl) == 0)
2966                flags |= NLM_F_DUMP;
2967
2968        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PARAM_GET, flags);
2969
2970        if (dl_argc(dl) > 0) {
2971                err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE |
2972                                        DL_OPT_PARAM_NAME, 0);
2973                if (err)
2974                        return err;
2975        }
2976
2977        pr_out_section_start(dl, "param");
2978        err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_param_show_cb, dl);
2979        pr_out_section_end(dl);
2980        return err;
2981}
2982
2983static int cmd_dev_param(struct dl *dl)
2984{
2985        if (dl_argv_match(dl, "help")) {
2986                cmd_dev_help();
2987                return 0;
2988        } else if (dl_argv_match(dl, "show") ||
2989                   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
2990                dl_arg_inc(dl);
2991                return cmd_dev_param_show(dl);
2992        } else if (dl_argv_match(dl, "set")) {
2993                dl_arg_inc(dl);
2994                return cmd_dev_param_set(dl);
2995        }
2996        pr_err("Command \"%s\" not found\n", dl_argv(dl));
2997        return -ENOENT;
2998}
2999
3000static void pr_out_action_stats(struct dl *dl, struct nlattr *action_stats)
3001{
3002        struct nlattr *tb_stats_entry[DEVLINK_ATTR_MAX + 1] = {};
3003        struct nlattr *nla_reload_stats_entry, *nla_limit, *nla_value;
3004        enum devlink_reload_limit limit;
3005        uint32_t value;
3006        int err;
3007
3008        mnl_attr_for_each_nested(nla_reload_stats_entry, action_stats) {
3009                err = mnl_attr_parse_nested(nla_reload_stats_entry, attr_cb,
3010                                            tb_stats_entry);
3011                if (err != MNL_CB_OK)
3012                        return;
3013
3014                nla_limit = tb_stats_entry[DEVLINK_ATTR_RELOAD_STATS_LIMIT];
3015                nla_value = tb_stats_entry[DEVLINK_ATTR_RELOAD_STATS_VALUE];
3016                if (!nla_limit || !nla_value)
3017                        return;
3018
3019                check_indent_newline(dl);
3020                limit = mnl_attr_get_u8(nla_limit);
3021                value = mnl_attr_get_u32(nla_value);
3022                print_uint_name_value(reload_limit_name(limit), value);
3023        }
3024}
3025
3026static void pr_out_reload_stats(struct dl *dl, struct nlattr *reload_stats)
3027{
3028        struct nlattr *nla_action_info, *nla_action, *nla_action_stats;
3029        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3030        enum devlink_reload_action action;
3031        int err;
3032
3033        mnl_attr_for_each_nested(nla_action_info, reload_stats) {
3034                err = mnl_attr_parse_nested(nla_action_info, attr_cb, tb);
3035                if (err != MNL_CB_OK)
3036                        return;
3037                nla_action = tb[DEVLINK_ATTR_RELOAD_ACTION];
3038                nla_action_stats = tb[DEVLINK_ATTR_RELOAD_ACTION_STATS];
3039                if (!nla_action || !nla_action_stats)
3040                        return;
3041
3042                action = mnl_attr_get_u8(nla_action);
3043                pr_out_object_start(dl, reload_action_name(action));
3044                pr_out_action_stats(dl, nla_action_stats);
3045                pr_out_object_end(dl);
3046        }
3047}
3048
3049static void pr_out_reload_data(struct dl *dl, struct nlattr **tb)
3050{
3051        struct nlattr *nla_reload_stats, *nla_remote_reload_stats;
3052        struct nlattr *tb_stats[DEVLINK_ATTR_MAX + 1] = {};
3053        uint8_t reload_failed = 0;
3054        int err;
3055
3056        if (tb[DEVLINK_ATTR_RELOAD_FAILED])
3057                reload_failed = mnl_attr_get_u8(tb[DEVLINK_ATTR_RELOAD_FAILED]);
3058
3059        if (reload_failed) {
3060                check_indent_newline(dl);
3061                print_bool(PRINT_ANY, "reload_failed", "reload_failed %s", true);
3062        }
3063        if (!tb[DEVLINK_ATTR_DEV_STATS] || !dl->stats)
3064                return;
3065        err = mnl_attr_parse_nested(tb[DEVLINK_ATTR_DEV_STATS], attr_cb,
3066                                    tb_stats);
3067        if (err != MNL_CB_OK)
3068                return;
3069
3070        pr_out_object_start(dl, "stats");
3071
3072        nla_reload_stats = tb_stats[DEVLINK_ATTR_RELOAD_STATS];
3073        if (nla_reload_stats) {
3074                pr_out_object_start(dl, "reload");
3075                pr_out_reload_stats(dl, nla_reload_stats);
3076                pr_out_object_end(dl);
3077        }
3078        nla_remote_reload_stats = tb_stats[DEVLINK_ATTR_REMOTE_RELOAD_STATS];
3079        if (nla_remote_reload_stats) {
3080                pr_out_object_start(dl, "remote_reload");
3081                pr_out_reload_stats(dl, nla_remote_reload_stats);
3082                pr_out_object_end(dl);
3083        }
3084
3085        pr_out_object_end(dl);
3086}
3087
3088
3089static void pr_out_dev(struct dl *dl, struct nlattr **tb)
3090{
3091        if ((tb[DEVLINK_ATTR_RELOAD_FAILED] && mnl_attr_get_u8(tb[DEVLINK_ATTR_RELOAD_FAILED])) ||
3092            (tb[DEVLINK_ATTR_DEV_STATS] && dl->stats)) {
3093                __pr_out_handle_start(dl, tb, true, false);
3094                pr_out_reload_data(dl, tb);
3095                pr_out_handle_end(dl);
3096        } else {
3097                pr_out_handle(dl, tb);
3098        }
3099}
3100
3101static int cmd_dev_show_cb(const struct nlmsghdr *nlh, void *data)
3102{
3103        struct dl *dl = data;
3104        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3105        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3106
3107        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3108        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
3109                return MNL_CB_ERROR;
3110
3111        pr_out_dev(dl, tb);
3112        return MNL_CB_OK;
3113}
3114
3115static int cmd_dev_show(struct dl *dl)
3116{
3117        struct nlmsghdr *nlh;
3118        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
3119        int err;
3120
3121        if (dl_argc(dl) == 0)
3122                flags |= NLM_F_DUMP;
3123
3124        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_GET, flags);
3125
3126        if (dl_argc(dl) > 0) {
3127                err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
3128                if (err)
3129                        return err;
3130        }
3131
3132        pr_out_section_start(dl, "dev");
3133        err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_show_cb, dl);
3134        pr_out_section_end(dl);
3135        return err;
3136}
3137
3138static void pr_out_reload_actions_performed(struct dl *dl, struct nlattr **tb)
3139{
3140        struct nlattr *nla_actions_performed;
3141        struct nla_bitfield32 *actions;
3142        uint32_t actions_performed;
3143        uint16_t len;
3144        int action;
3145
3146        if (!tb[DEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED])
3147                return;
3148
3149        nla_actions_performed = tb[DEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED];
3150        len = mnl_attr_get_payload_len(nla_actions_performed);
3151        if (len != sizeof(*actions))
3152                return;
3153        actions = mnl_attr_get_payload(nla_actions_performed);
3154        if (!actions)
3155                return;
3156        g_new_line_count = 1; /* Avoid extra new line in non-json print */
3157        pr_out_array_start(dl, "reload_actions_performed");
3158        actions_performed = actions->value & actions->selector;
3159        for (action = 0; action <= DEVLINK_RELOAD_ACTION_MAX; action++) {
3160                if (BIT(action) & actions_performed) {
3161                        check_indent_newline(dl);
3162                        print_string(PRINT_ANY, NULL, "%s",
3163                                     reload_action_name(action));
3164                }
3165        }
3166        pr_out_array_end(dl);
3167        if (!dl->json_output)
3168                __pr_out_newline();
3169}
3170
3171static int cmd_dev_reload_cb(const struct nlmsghdr *nlh, void *data)
3172{
3173        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3174        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3175        struct dl *dl = data;
3176
3177        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3178        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3179            !tb[DEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED])
3180                return MNL_CB_ERROR;
3181
3182        pr_out_section_start(dl, "reload");
3183        pr_out_reload_actions_performed(dl, tb);
3184        pr_out_section_end(dl);
3185
3186        return MNL_CB_OK;
3187}
3188
3189static int cmd_dev_reload(struct dl *dl)
3190{
3191        struct nlmsghdr *nlh;
3192        int err;
3193
3194        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
3195                cmd_dev_help();
3196                return 0;
3197        }
3198
3199        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RELOAD,
3200                               NLM_F_REQUEST | NLM_F_ACK);
3201
3202        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE,
3203                                DL_OPT_NETNS | DL_OPT_RELOAD_ACTION |
3204                                DL_OPT_RELOAD_LIMIT);
3205        if (err)
3206                return err;
3207
3208        return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_reload_cb, dl);
3209}
3210
3211static void pr_out_versions_single(struct dl *dl, const struct nlmsghdr *nlh,
3212                                   const char *name, int type)
3213{
3214        struct nlattr *version;
3215
3216        mnl_attr_for_each(version, nlh, sizeof(struct genlmsghdr)) {
3217                struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3218                const char *ver_value;
3219                const char *ver_name;
3220                int err;
3221
3222                if (mnl_attr_get_type(version) != type)
3223                        continue;
3224
3225                err = mnl_attr_parse_nested(version, attr_cb, tb);
3226                if (err != MNL_CB_OK)
3227                        continue;
3228
3229                if (!tb[DEVLINK_ATTR_INFO_VERSION_NAME] ||
3230                    !tb[DEVLINK_ATTR_INFO_VERSION_VALUE])
3231                        continue;
3232
3233                if (name) {
3234                        pr_out_object_start(dl, name);
3235                        name = NULL;
3236                }
3237
3238                ver_name = mnl_attr_get_str(tb[DEVLINK_ATTR_INFO_VERSION_NAME]);
3239                ver_value = mnl_attr_get_str(tb[DEVLINK_ATTR_INFO_VERSION_VALUE]);
3240
3241                check_indent_newline(dl);
3242                print_string_name_value(ver_name, ver_value);
3243                if (!dl->json_output)
3244                        __pr_out_newline();
3245        }
3246
3247        if (!name)
3248                pr_out_object_end(dl);
3249}
3250
3251static void pr_out_info(struct dl *dl, const struct nlmsghdr *nlh,
3252                        struct nlattr **tb, bool has_versions)
3253{
3254        __pr_out_handle_start(dl, tb, true, false);
3255
3256        __pr_out_indent_inc();
3257        if (tb[DEVLINK_ATTR_INFO_DRIVER_NAME]) {
3258                struct nlattr *nla_drv = tb[DEVLINK_ATTR_INFO_DRIVER_NAME];
3259
3260                if (!dl->json_output)
3261                        __pr_out_newline();
3262                check_indent_newline(dl);
3263                print_string(PRINT_ANY, "driver", "driver %s",
3264                             mnl_attr_get_str(nla_drv));
3265        }
3266
3267        if (tb[DEVLINK_ATTR_INFO_SERIAL_NUMBER]) {
3268                struct nlattr *nla_sn = tb[DEVLINK_ATTR_INFO_SERIAL_NUMBER];
3269
3270                if (!dl->json_output)
3271                        __pr_out_newline();
3272                check_indent_newline(dl);
3273                print_string(PRINT_ANY, "serial_number", "serial_number %s",
3274                             mnl_attr_get_str(nla_sn));
3275        }
3276
3277        if (tb[DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER]) {
3278                struct nlattr *nla_bsn = tb[DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER];
3279
3280                if (!dl->json_output)
3281                        __pr_out_newline();
3282                check_indent_newline(dl);
3283                print_string(PRINT_ANY, "board.serial_number", "board.serial_number %s",
3284                             mnl_attr_get_str(nla_bsn));
3285        }
3286        __pr_out_indent_dec();
3287
3288        if (has_versions) {
3289                pr_out_object_start(dl, "versions");
3290
3291                pr_out_versions_single(dl, nlh, "fixed",
3292                                       DEVLINK_ATTR_INFO_VERSION_FIXED);
3293                pr_out_versions_single(dl, nlh, "running",
3294                                       DEVLINK_ATTR_INFO_VERSION_RUNNING);
3295                pr_out_versions_single(dl, nlh, "stored",
3296                                       DEVLINK_ATTR_INFO_VERSION_STORED);
3297
3298                pr_out_object_end(dl);
3299        }
3300
3301        pr_out_handle_end(dl);
3302}
3303
3304static int cmd_versions_show_cb(const struct nlmsghdr *nlh, void *data)
3305{
3306        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3307        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3308        bool has_versions, has_info;
3309        struct dl *dl = data;
3310
3311        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3312
3313        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
3314                return MNL_CB_ERROR;
3315
3316        has_versions = tb[DEVLINK_ATTR_INFO_VERSION_FIXED] ||
3317                tb[DEVLINK_ATTR_INFO_VERSION_RUNNING] ||
3318                tb[DEVLINK_ATTR_INFO_VERSION_STORED];
3319        has_info = tb[DEVLINK_ATTR_INFO_DRIVER_NAME] ||
3320                tb[DEVLINK_ATTR_INFO_SERIAL_NUMBER] ||
3321                tb[DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER] ||
3322                has_versions;
3323
3324        if (has_info)
3325                pr_out_info(dl, nlh, tb, has_versions);
3326
3327        return MNL_CB_OK;
3328}
3329
3330static int cmd_dev_info(struct dl *dl)
3331{
3332        struct nlmsghdr *nlh;
3333        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
3334        int err;
3335
3336        if (dl_argv_match(dl, "help")) {
3337                cmd_dev_help();
3338                return 0;
3339        }
3340
3341        if (dl_argc(dl) == 0)
3342                flags |= NLM_F_DUMP;
3343
3344        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_INFO_GET, flags);
3345
3346        if (dl_argc(dl) > 0) {
3347                err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
3348                if (err)
3349                        return err;
3350        }
3351
3352        pr_out_section_start(dl, "info");
3353        err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_versions_show_cb, dl);
3354        pr_out_section_end(dl);
3355        return err;
3356}
3357
3358struct cmd_dev_flash_status_ctx {
3359        struct dl *dl;
3360        struct timespec time_of_last_status;
3361        uint64_t status_msg_timeout;
3362        size_t elapsed_time_msg_len;
3363        char *last_msg;
3364        char *last_component;
3365        uint8_t not_first:1,
3366                last_pc:1,
3367                received_end:1,
3368                flash_done:1;
3369};
3370
3371static int nullstrcmp(const char *str1, const char *str2)
3372{
3373        if (str1 && str2)
3374                return strcmp(str1, str2);
3375        if (!str1 && !str2)
3376                return 0;
3377        return str1 ? 1 : -1;
3378}
3379
3380static void cmd_dev_flash_clear_elapsed_time(struct cmd_dev_flash_status_ctx *ctx)
3381{
3382        int i;
3383
3384        for (i = 0; i < ctx->elapsed_time_msg_len; i++)
3385                pr_out_tty("\b \b");
3386
3387        ctx->elapsed_time_msg_len = 0;
3388}
3389
3390static int cmd_dev_flash_status_cb(const struct nlmsghdr *nlh, void *data)
3391{
3392        struct cmd_dev_flash_status_ctx *ctx = data;
3393        struct dl_opts *opts = &ctx->dl->opts;
3394        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3395        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3396        const char *component = NULL;
3397        uint64_t done = 0, total = 0;
3398        const char *msg = NULL;
3399        const char *bus_name;
3400        const char *dev_name;
3401
3402        cmd_dev_flash_clear_elapsed_time(ctx);
3403
3404        if (genl->cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS &&
3405            genl->cmd != DEVLINK_CMD_FLASH_UPDATE_END)
3406                return MNL_CB_STOP;
3407
3408        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3409        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
3410                return MNL_CB_ERROR;
3411        bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
3412        dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
3413        if (strcmp(bus_name, opts->bus_name) ||
3414            strcmp(dev_name, opts->dev_name))
3415                return MNL_CB_ERROR;
3416
3417        if (genl->cmd == DEVLINK_CMD_FLASH_UPDATE_END && ctx->not_first) {
3418                pr_out("\n");
3419                free(ctx->last_msg);
3420                free(ctx->last_component);
3421                ctx->received_end = 1;
3422                return MNL_CB_STOP;
3423        }
3424
3425        if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG])
3426                msg = mnl_attr_get_str(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG]);
3427        if (tb[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT])
3428                component = mnl_attr_get_str(tb[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT]);
3429        if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE])
3430                done = mnl_attr_get_u64(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE]);
3431        if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL])
3432                total = mnl_attr_get_u64(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL]);
3433        if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TIMEOUT])
3434                ctx->status_msg_timeout = mnl_attr_get_u64(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TIMEOUT]);
3435        else
3436                ctx->status_msg_timeout = 0;
3437
3438        if (!nullstrcmp(msg, ctx->last_msg) &&
3439            !nullstrcmp(component, ctx->last_component) &&
3440            ctx->last_pc && ctx->not_first) {
3441                pr_out_tty("\b\b\b\b\b"); /* clean percentage */
3442        } else {
3443                /* only update the last status timestamp if the message changed */
3444                clock_gettime(CLOCK_MONOTONIC, &ctx->time_of_last_status);
3445
3446                if (ctx->not_first)
3447                        pr_out("\n");
3448                if (component) {
3449                        pr_out("[%s] ", component);
3450                        free(ctx->last_component);
3451                        ctx->last_component = strdup(component);
3452                }
3453                if (msg) {
3454                        pr_out("%s", msg);
3455                        free(ctx->last_msg);
3456                        ctx->last_msg = strdup(msg);
3457                }
3458        }
3459        if (total) {
3460                pr_out_tty(" %3lu%%", (done * 100) / total);
3461                ctx->last_pc = 1;
3462        } else {
3463                ctx->last_pc = 0;
3464        }
3465        fflush(stdout);
3466        ctx->not_first = 1;
3467
3468        return MNL_CB_STOP;
3469}
3470
3471static void cmd_dev_flash_time_elapsed(struct cmd_dev_flash_status_ctx *ctx)
3472{
3473        struct timespec now, res;
3474
3475        clock_gettime(CLOCK_MONOTONIC, &now);
3476
3477        res.tv_sec = now.tv_sec - ctx->time_of_last_status.tv_sec;
3478        res.tv_nsec = now.tv_nsec - ctx->time_of_last_status.tv_nsec;
3479        if (res.tv_nsec < 0) {
3480                res.tv_sec--;
3481                res.tv_nsec += 1000000000L;
3482        }
3483
3484        /* Only begin displaying an elapsed time message if we've waited a few
3485         * seconds with no response, or the status message included a timeout
3486         * value.
3487         */
3488        if (res.tv_sec > 2 || ctx->status_msg_timeout) {
3489                uint64_t elapsed_m, elapsed_s;
3490                char msg[128];
3491                size_t len;
3492
3493                /* clear the last elapsed time message, if we have one */
3494                cmd_dev_flash_clear_elapsed_time(ctx);
3495
3496                elapsed_m = res.tv_sec / 60;
3497                elapsed_s = res.tv_sec % 60;
3498
3499                /**
3500                 * If we've elapsed a few seconds without receiving any status
3501                 * notification from the device, we display a time elapsed
3502                 * message. This has a few possible formats:
3503                 *
3504                 * 1) just time elapsed, when no timeout was provided
3505                 *    " ( Xm Ys )"
3506                 * 2) time elapsed out of a timeout that came from the device
3507                 *    driver via DEVLINK_CMD_FLASH_UPDATE_STATUS_TIMEOUT
3508                 *    " ( Xm Ys : Am Ys)"
3509                 * 3) time elapsed if we still receive no status after
3510                 *    reaching the provided timeout.
3511                 *    " ( Xm Ys : timeout reached )"
3512                 */
3513                if (!ctx->status_msg_timeout) {
3514                        len = snprintf(msg, sizeof(msg),
3515                                       " ( %lum %lus )", elapsed_m, elapsed_s);
3516                } else if (res.tv_sec <= ctx->status_msg_timeout) {
3517                        uint64_t timeout_m, timeout_s;
3518
3519                        timeout_m = ctx->status_msg_timeout / 60;
3520                        timeout_s = ctx->status_msg_timeout % 60;
3521
3522                        len = snprintf(msg, sizeof(msg),
3523                                       " ( %lum %lus : %lum %lus )",
3524                                       elapsed_m, elapsed_s, timeout_m, timeout_s);
3525                } else {
3526                        len = snprintf(msg, sizeof(msg),
3527                                       " ( %lum %lus : timeout reached )", elapsed_m, elapsed_s);
3528                }
3529
3530                ctx->elapsed_time_msg_len = len;
3531
3532                pr_out_tty("%s", msg);
3533                fflush(stdout);
3534        }
3535}
3536
3537static int cmd_dev_flash_fds_process(struct cmd_dev_flash_status_ctx *ctx,
3538                                     struct mnlg_socket *nlg_ntf,
3539                                     int pipe_r)
3540{
3541        int nlfd = mnlg_socket_get_fd(nlg_ntf);
3542        struct timeval timeout;
3543        fd_set fds[3];
3544        int fdmax;
3545        int i;
3546        int err;
3547        int err2;
3548
3549        for (i = 0; i < 3; i++)
3550                FD_ZERO(&fds[i]);
3551        FD_SET(pipe_r, &fds[0]);
3552        fdmax = pipe_r + 1;
3553        FD_SET(nlfd, &fds[0]);
3554        if (nlfd >= fdmax)
3555                fdmax = nlfd + 1;
3556
3557        /* select only for a short while (1/10th of a second) in order to
3558         * allow periodically updating the screen with an elapsed time
3559         * indicator.
3560         */
3561        timeout.tv_sec = 0;
3562        timeout.tv_usec = 100000;
3563
3564        while (select(fdmax, &fds[0], &fds[1], &fds[2], &timeout) < 0) {
3565                if (errno == EINTR)
3566                        continue;
3567                pr_err("select() failed\n");
3568                return -errno;
3569        }
3570        if (FD_ISSET(nlfd, &fds[0])) {
3571                err = _mnlg_socket_recv_run(nlg_ntf,
3572                                            cmd_dev_flash_status_cb, ctx);
3573                if (err)
3574                        return err;
3575        }
3576        if (FD_ISSET(pipe_r, &fds[0])) {
3577                err = read(pipe_r, &err2, sizeof(err2));
3578                if (err == -1) {
3579                        pr_err("Failed to read pipe\n");
3580                        return -errno;
3581                }
3582                if (err2)
3583                        return err2;
3584                ctx->flash_done = 1;
3585        }
3586        cmd_dev_flash_time_elapsed(ctx);
3587        return 0;
3588}
3589
3590
3591static int cmd_dev_flash(struct dl *dl)
3592{
3593        struct cmd_dev_flash_status_ctx ctx = {.dl = dl,};
3594        struct mnlg_socket *nlg_ntf;
3595        struct nlmsghdr *nlh;
3596        int pipe_r, pipe_w;
3597        int pipe_fds[2];
3598        pid_t pid;
3599        int err;
3600
3601        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
3602                cmd_dev_help();
3603                return 0;
3604        }
3605
3606        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_FLASH_UPDATE,
3607                               NLM_F_REQUEST | NLM_F_ACK);
3608
3609        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_FLASH_FILE_NAME,
3610                                DL_OPT_FLASH_COMPONENT | DL_OPT_FLASH_OVERWRITE);
3611        if (err)
3612                return err;
3613
3614        nlg_ntf = mnlg_socket_open(DEVLINK_GENL_NAME, DEVLINK_GENL_VERSION);
3615        if (!nlg_ntf)
3616                return err;
3617
3618        err = _mnlg_socket_group_add(nlg_ntf, DEVLINK_GENL_MCGRP_CONFIG_NAME);
3619        if (err)
3620                goto err_socket;
3621
3622        err = pipe(pipe_fds);
3623        if (err == -1) {
3624                err = -errno;
3625                goto err_socket;
3626        }
3627        pipe_r = pipe_fds[0];
3628        pipe_w = pipe_fds[1];
3629
3630        pid = fork();
3631        if (pid == -1) {
3632                close(pipe_w);
3633                err = -errno;
3634                goto out;
3635        } else if (!pid) {
3636                /* In child, just execute the flash and pass returned
3637                 * value through pipe once it is done.
3638                 */
3639                int cc;
3640
3641                close(pipe_r);
3642                err = _mnlg_socket_send(dl->nlg, nlh);
3643                cc = write(pipe_w, &err, sizeof(err));
3644                close(pipe_w);
3645                exit(cc != sizeof(err));
3646        }
3647        close(pipe_w);
3648
3649        /* initialize starting time to allow comparison for when to begin
3650         * displaying a time elapsed message.
3651         */
3652        clock_gettime(CLOCK_MONOTONIC, &ctx.time_of_last_status);
3653
3654        do {
3655                err = cmd_dev_flash_fds_process(&ctx, nlg_ntf, pipe_r);
3656                if (err)
3657                        goto out;
3658        } while (!ctx.flash_done || (ctx.not_first && !ctx.received_end));
3659
3660        err = _mnlg_socket_recv_run(dl->nlg, NULL, NULL);
3661out:
3662        close(pipe_r);
3663err_socket:
3664        mnlg_socket_close(nlg_ntf);
3665        return err;
3666}
3667
3668static int cmd_dev(struct dl *dl)
3669{
3670        if (dl_argv_match(dl, "help")) {
3671                cmd_dev_help();
3672                return 0;
3673        } else if (dl_argv_match(dl, "show") ||
3674                   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
3675                dl_arg_inc(dl);
3676                return cmd_dev_show(dl);
3677        } else if (dl_argv_match(dl, "eswitch")) {
3678                dl_arg_inc(dl);
3679                return cmd_dev_eswitch(dl);
3680        } else if (dl_argv_match(dl, "reload")) {
3681                dl_arg_inc(dl);
3682                return cmd_dev_reload(dl);
3683        } else if (dl_argv_match(dl, "param")) {
3684                dl_arg_inc(dl);
3685                return cmd_dev_param(dl);
3686        } else if (dl_argv_match(dl, "info")) {
3687                dl_arg_inc(dl);
3688                return cmd_dev_info(dl);
3689        } else if (dl_argv_match(dl, "flash")) {
3690                dl_arg_inc(dl);
3691                return cmd_dev_flash(dl);
3692        }
3693        pr_err("Command \"%s\" not found\n", dl_argv(dl));
3694        return -ENOENT;
3695}
3696
3697static void cmd_port_help(void)
3698{
3699        pr_err("Usage: devlink port show [ DEV/PORT_INDEX ]\n");
3700        pr_err("       devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n");
3701        pr_err("       devlink port split DEV/PORT_INDEX count COUNT\n");
3702        pr_err("       devlink port unsplit DEV/PORT_INDEX\n");
3703        pr_err("       devlink port function set DEV/PORT_INDEX [ hw_addr ADDR ]\n");
3704        pr_err("       devlink port health show [ DEV/PORT_INDEX reporter REPORTER_NAME ]\n");
3705}
3706
3707static const char *port_type_name(uint32_t type)
3708{
3709        switch (type) {
3710        case DEVLINK_PORT_TYPE_NOTSET: return "notset";
3711        case DEVLINK_PORT_TYPE_AUTO: return "auto";
3712        case DEVLINK_PORT_TYPE_ETH: return "eth";
3713        case DEVLINK_PORT_TYPE_IB: return "ib";
3714        default: return "<unknown type>";
3715        }
3716}
3717
3718static const char *port_flavour_name(uint16_t flavour)
3719{
3720        switch (flavour) {
3721        case DEVLINK_PORT_FLAVOUR_PHYSICAL:
3722                return "physical";
3723        case DEVLINK_PORT_FLAVOUR_CPU:
3724                return "cpu";
3725        case DEVLINK_PORT_FLAVOUR_DSA:
3726                return "dsa";
3727        case DEVLINK_PORT_FLAVOUR_PCI_PF:
3728                return "pcipf";
3729        case DEVLINK_PORT_FLAVOUR_PCI_VF:
3730                return "pcivf";
3731        case DEVLINK_PORT_FLAVOUR_VIRTUAL:
3732                return "virtual";
3733        default:
3734                return "<unknown flavour>";
3735        }
3736}
3737
3738static void pr_out_port_pfvf_num(struct dl *dl, struct nlattr **tb)
3739{
3740        uint16_t fn_num;
3741
3742        if (tb[DEVLINK_ATTR_PORT_CONTROLLER_NUMBER])
3743                print_uint(PRINT_ANY, "controller", " controller %u",
3744                           mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_CONTROLLER_NUMBER]));
3745        if (tb[DEVLINK_ATTR_PORT_PCI_PF_NUMBER]) {
3746                fn_num = mnl_attr_get_u16(tb[DEVLINK_ATTR_PORT_PCI_PF_NUMBER]);
3747                print_uint(PRINT_ANY, "pfnum", " pfnum %u", fn_num);
3748        }
3749        if (tb[DEVLINK_ATTR_PORT_PCI_VF_NUMBER]) {
3750                fn_num = mnl_attr_get_u16(tb[DEVLINK_ATTR_PORT_PCI_VF_NUMBER]);
3751                print_uint(PRINT_ANY, "vfnum", " vfnum %u", fn_num);
3752        }
3753        if (tb[DEVLINK_ATTR_PORT_EXTERNAL]) {
3754                uint8_t external;
3755
3756                external = mnl_attr_get_u8(tb[DEVLINK_ATTR_PORT_EXTERNAL]);
3757                print_bool(PRINT_ANY, "external", " external %s", external);
3758        }
3759}
3760
3761static void pr_out_port_function(struct dl *dl, struct nlattr **tb_port)
3762{
3763        struct nlattr *tb[DEVLINK_PORT_FUNCTION_ATTR_MAX + 1] = {};
3764        unsigned char *data;
3765        SPRINT_BUF(hw_addr);
3766        uint32_t len;
3767        int err;
3768
3769        if (!tb_port[DEVLINK_ATTR_PORT_FUNCTION])
3770                return;
3771
3772        err = mnl_attr_parse_nested(tb_port[DEVLINK_ATTR_PORT_FUNCTION],
3773                                    function_attr_cb, tb);
3774        if (err != MNL_CB_OK)
3775                return;
3776
3777        if (!tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR])
3778                return;
3779
3780        len = mnl_attr_get_payload_len(tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR]);
3781        data = mnl_attr_get_payload(tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR]);
3782
3783        pr_out_object_start(dl, "function");
3784        check_indent_newline(dl);
3785        print_string(PRINT_ANY, "hw_addr", "hw_addr %s",
3786                     ll_addr_n2a(data, len, 0, hw_addr, sizeof(hw_addr)));
3787        if (!dl->json_output)
3788                __pr_out_indent_dec();
3789        pr_out_object_end(dl);
3790}
3791
3792static void pr_out_port(struct dl *dl, struct nlattr **tb)
3793{
3794        struct nlattr *pt_attr = tb[DEVLINK_ATTR_PORT_TYPE];
3795        struct nlattr *dpt_attr = tb[DEVLINK_ATTR_PORT_DESIRED_TYPE];
3796
3797        pr_out_port_handle_start(dl, tb, false);
3798        check_indent_newline(dl);
3799        if (pt_attr) {
3800                uint16_t port_type = mnl_attr_get_u16(pt_attr);
3801
3802                print_string(PRINT_ANY, "type", "type %s",
3803                             port_type_name(port_type));
3804                if (dpt_attr) {
3805                        uint16_t des_port_type = mnl_attr_get_u16(dpt_attr);
3806
3807                        if (port_type != des_port_type)
3808                                print_string(PRINT_ANY, "des_type", " des_type %s",
3809                                             port_type_name(des_port_type));
3810                }
3811        }
3812        if (tb[DEVLINK_ATTR_PORT_NETDEV_NAME]) {
3813                print_string(PRINT_ANY, "netdev", " netdev %s",
3814                             mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME]));
3815        }
3816        if (tb[DEVLINK_ATTR_PORT_IBDEV_NAME]) {
3817                print_string(PRINT_ANY, "ibdev", " ibdev %s",
3818                             mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_IBDEV_NAME]));
3819                }
3820        if (tb[DEVLINK_ATTR_PORT_FLAVOUR]) {
3821                uint16_t port_flavour =
3822                                mnl_attr_get_u16(tb[DEVLINK_ATTR_PORT_FLAVOUR]);
3823
3824                print_string(PRINT_ANY, "flavour", " flavour %s",
3825                             port_flavour_name(port_flavour));
3826
3827                switch (port_flavour) {
3828                case DEVLINK_PORT_FLAVOUR_PCI_PF:
3829                case DEVLINK_PORT_FLAVOUR_PCI_VF:
3830                        pr_out_port_pfvf_num(dl, tb);
3831                        break;
3832                default:
3833                        break;
3834                }
3835        }
3836        if (tb[DEVLINK_ATTR_PORT_NUMBER]) {
3837                uint32_t port_number;
3838
3839                port_number = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_NUMBER]);
3840                print_uint(PRINT_ANY, "port", " port %u", port_number);
3841        }
3842        if (tb[DEVLINK_ATTR_PORT_SPLIT_GROUP])
3843                print_uint(PRINT_ANY, "split_group", " split_group %u",
3844                           mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_SPLIT_GROUP]));
3845        if (tb[DEVLINK_ATTR_PORT_SPLITTABLE])
3846                print_bool(PRINT_ANY, "splittable", " splittable %s",
3847                           mnl_attr_get_u8(tb[DEVLINK_ATTR_PORT_SPLITTABLE]));
3848        if (tb[DEVLINK_ATTR_PORT_LANES])
3849                print_uint(PRINT_ANY, "lanes", " lanes %u",
3850                           mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_LANES]));
3851
3852        pr_out_port_function(dl, tb);
3853        pr_out_port_handle_end(dl);
3854}
3855
3856static int cmd_port_show_cb(const struct nlmsghdr *nlh, void *data)
3857{
3858        struct dl *dl = data;
3859        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3860        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3861
3862        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3863        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3864            !tb[DEVLINK_ATTR_PORT_INDEX])
3865                return MNL_CB_ERROR;
3866        pr_out_port(dl, tb);
3867        return MNL_CB_OK;
3868}
3869
3870static int cmd_port_show(struct dl *dl)
3871{
3872        struct nlmsghdr *nlh;
3873        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
3874        int err;
3875
3876        if (dl_argc(dl) == 0)
3877                flags |= NLM_F_DUMP;
3878
3879        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_GET, flags);
3880
3881        if (dl_argc(dl) > 0) {
3882                err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
3883                if (err)
3884                        return err;
3885        }
3886
3887        pr_out_section_start(dl, "port");
3888        err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_port_show_cb, dl);
3889        pr_out_section_end(dl);
3890        return err;
3891}
3892
3893static int cmd_port_set(struct dl *dl)
3894{
3895        struct nlmsghdr *nlh;
3896        int err;
3897
3898        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SET,
3899                               NLM_F_REQUEST | NLM_F_ACK);
3900
3901        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_TYPE, 0);
3902        if (err)
3903                return err;
3904
3905        return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
3906}
3907
3908static int cmd_port_split(struct dl *dl)
3909{
3910        struct nlmsghdr *nlh;
3911        int err;
3912
3913        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SPLIT,
3914                               NLM_F_REQUEST | NLM_F_ACK);
3915
3916        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_COUNT, 0);
3917        if (err)
3918                return err;
3919
3920        return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
3921}
3922
3923static int cmd_port_unsplit(struct dl *dl)
3924{
3925        struct nlmsghdr *nlh;
3926        int err;
3927
3928        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_UNSPLIT,
3929                               NLM_F_REQUEST | NLM_F_ACK);
3930
3931        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
3932        if (err)
3933                return err;
3934
3935        return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
3936}
3937
3938static void cmd_port_function_help(void)
3939{
3940        pr_err("Usage: devlink port function set DEV/PORT_INDEX [ hw_addr ADDR ]\n");
3941}
3942
3943static int cmd_port_function_set(struct dl *dl)
3944{
3945        struct nlmsghdr *nlh;
3946        int err;
3947
3948        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SET, NLM_F_REQUEST | NLM_F_ACK);
3949
3950        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_FUNCTION_HW_ADDR, 0);
3951        if (err)
3952                return err;
3953
3954        return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
3955}
3956
3957static int cmd_port_function(struct dl *dl)
3958{
3959        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
3960                cmd_port_function_help();
3961                return 0;
3962        } else if (dl_argv_match(dl, "set")) {
3963                dl_arg_inc(dl);
3964                return cmd_port_function_set(dl);
3965        }
3966        pr_err("Command \"%s\" not found\n", dl_argv(dl));
3967        return -ENOENT;
3968}
3969
3970static int cmd_health(struct dl *dl);
3971static int __cmd_health_show(struct dl *dl, bool show_device, bool show_port);
3972
3973static int cmd_port(struct dl *dl)
3974{
3975        if (dl_argv_match(dl, "help")) {
3976                cmd_port_help();
3977                return 0;
3978        } else if (dl_argv_match(dl, "show") ||
3979                   dl_argv_match(dl, "list") ||  dl_no_arg(dl)) {
3980                dl_arg_inc(dl);
3981                return cmd_port_show(dl);
3982        } else if (dl_argv_match(dl, "set")) {
3983                dl_arg_inc(dl);
3984                return cmd_port_set(dl);
3985        } else if (dl_argv_match(dl, "split")) {
3986                dl_arg_inc(dl);
3987                return cmd_port_split(dl);
3988        } else if (dl_argv_match(dl, "unsplit")) {
3989                dl_arg_inc(dl);
3990                return cmd_port_unsplit(dl);
3991        } else if (dl_argv_match(dl, "function")) {
3992                dl_arg_inc(dl);
3993                return cmd_port_function(dl);
3994        } else if (dl_argv_match(dl, "health")) {
3995                dl_arg_inc(dl);
3996                if (dl_argv_match(dl, "list") || dl_no_arg(dl)
3997                    || (dl_argv_match(dl, "show") && dl_argc(dl) == 1)) {
3998                        dl_arg_inc(dl);
3999                        return __cmd_health_show(dl, false, true);
4000                } else {
4001                        return cmd_health(dl);
4002                }
4003        }
4004        pr_err("Command \"%s\" not found\n", dl_argv(dl));
4005        return -ENOENT;
4006}
4007
4008static void cmd_sb_help(void)
4009{
4010        pr_err("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n");
4011        pr_err("       devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n");
4012        pr_err("       devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n");
4013        pr_err("                           size POOL_SIZE thtype { static | dynamic }\n");
4014        pr_err("       devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n");
4015        pr_err("                                   pool POOL_INDEX ]\n");
4016        pr_err("       devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n");
4017        pr_err("                                pool POOL_INDEX th THRESHOLD\n");
4018        pr_err("       devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
4019        pr_err("                                 type { ingress | egress } ]\n");
4020        pr_err("       devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
4021        pr_err("                              type { ingress | egress } pool POOL_INDEX\n");
4022        pr_err("                              th THRESHOLD\n");
4023        pr_err("       devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n");
4024        pr_err("       devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n");
4025        pr_err("       devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n");
4026}
4027
4028static void pr_out_sb(struct dl *dl, struct nlattr **tb)
4029{
4030        pr_out_handle_start_arr(dl, tb);
4031        check_indent_newline(dl);
4032        print_uint(PRINT_ANY, "sb", "sb %u",
4033                   mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
4034        print_uint(PRINT_ANY, "size", " size %u",
4035                   mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_SIZE]));
4036        print_uint(PRINT_ANY, "ing_pools", " ing_pools %u",
4037                   mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT]));
4038        print_uint(PRINT_ANY, "eg_pools", " eg_pools %u",
4039                   mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT]));
4040        print_uint(PRINT_ANY, "ing_tcs", " ing_tcs %u",
4041                   mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT]));
4042        print_uint(PRINT_ANY, "eg_tcs", " eg_tcs %u",
4043                   mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT]));
4044        pr_out_handle_end(dl);
4045}
4046
4047static int cmd_sb_show_cb(const struct nlmsghdr *nlh, void *data)
4048{
4049        struct dl *dl = data;
4050        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4051        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4052
4053        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4054        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4055            !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_SIZE] ||
4056            !tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT] ||
4057            !tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT] ||
4058            !tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT] ||
4059            !tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT])
4060                return MNL_CB_ERROR;
4061        pr_out_sb(dl, tb);
4062        return MNL_CB_OK;
4063}
4064
4065static int cmd_sb_show(struct dl *dl)
4066{
4067        struct nlmsghdr *nlh;
4068        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
4069        int err;
4070
4071        if (dl_argc(dl) == 0)
4072                flags |= NLM_F_DUMP;
4073
4074        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_GET, flags);
4075
4076        if (dl_argc(dl) > 0) {
4077                err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB);
4078                if (err)
4079                        return err;
4080        }
4081
4082        pr_out_section_start(dl, "sb");
4083        err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_show_cb, dl);
4084        pr_out_section_end(dl);
4085        return err;
4086}
4087
4088static const char *pool_type_name(uint8_t type)
4089{
4090        switch (type) {
4091        case DEVLINK_SB_POOL_TYPE_INGRESS: return "ingress";
4092        case DEVLINK_SB_POOL_TYPE_EGRESS: return "egress";
4093        default: return "<unknown type>";
4094        }
4095}
4096
4097static const char *threshold_type_name(uint8_t type)
4098{
4099        switch (type) {
4100        case DEVLINK_SB_THRESHOLD_TYPE_STATIC: return "static";
4101        case DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC: return "dynamic";
4102        default: return "<unknown type>";
4103        }
4104}
4105
4106static void pr_out_sb_pool(struct dl *dl, struct nlattr **tb)
4107{
4108        pr_out_handle_start_arr(dl, tb);
4109        check_indent_newline(dl);
4110        print_uint(PRINT_ANY, "sb", "sb %u",
4111                   mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
4112        print_uint(PRINT_ANY, "pool", " pool %u",
4113                   mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]));
4114        print_string(PRINT_ANY, "type", " type %s",
4115                     pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])));
4116        print_uint(PRINT_ANY, "size", " size %u",
4117                   mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_SIZE]));
4118        print_string(PRINT_ANY, "thtype", " thtype %s",
4119                     threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])));
4120        if (tb[DEVLINK_ATTR_SB_POOL_CELL_SIZE])
4121                print_uint(PRINT_ANY, "cell_size", " cell size %u",
4122                           mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_CELL_SIZE]));
4123        pr_out_handle_end(dl);
4124}
4125
4126static int cmd_sb_pool_show_cb(const struct nlmsghdr *nlh, void *data)
4127{
4128        struct dl *dl = data;
4129        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4130        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4131
4132        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4133        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4134            !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_INDEX] ||
4135            !tb[DEVLINK_ATTR_SB_POOL_TYPE] || !tb[DEVLINK_ATTR_SB_POOL_SIZE] ||
4136            !tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])
4137                return MNL_CB_ERROR;
4138        pr_out_sb_pool(dl, tb);
4139        return MNL_CB_OK;
4140}
4141
4142static int cmd_sb_pool_show(struct dl *dl)
4143{
4144        struct nlmsghdr *nlh;
4145        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
4146        int err;
4147
4148        if (dl_argc(dl) == 0)
4149                flags |= NLM_F_DUMP;
4150
4151        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_GET, flags);
4152
4153        if (dl_argc(dl) > 0) {
4154                err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL,
4155                                        DL_OPT_SB);
4156                if (err)
4157                        return err;
4158        }
4159
4160        pr_out_section_start(dl, "pool");
4161        err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_pool_show_cb, dl);
4162        pr_out_section_end(dl);
4163        return err;
4164}
4165
4166static int cmd_sb_pool_set(struct dl *dl)
4167{
4168        struct nlmsghdr *nlh;
4169        int err;
4170
4171        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_SET,
4172                               NLM_F_REQUEST | NLM_F_ACK);
4173
4174        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL |
4175                                DL_OPT_SB_SIZE | DL_OPT_SB_THTYPE, DL_OPT_SB);
4176        if (err)
4177                return err;
4178
4179        return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
4180}
4181
4182static int cmd_sb_pool(struct dl *dl)
4183{
4184        if (dl_argv_match(dl, "help")) {
4185                cmd_sb_help();
4186                return 0;
4187        } else if (dl_argv_match(dl, "show") ||
4188                   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
4189                dl_arg_inc(dl);
4190                return cmd_sb_pool_show(dl);
4191        } else if (dl_argv_match(dl, "set")) {
4192                dl_arg_inc(dl);
4193                return cmd_sb_pool_set(dl);
4194        }
4195        pr_err("Command \"%s\" not found\n", dl_argv(dl));
4196        return -ENOENT;
4197}
4198
4199static void pr_out_sb_port_pool(struct dl *dl, struct nlattr **tb)
4200{
4201        pr_out_port_handle_start_arr(dl, tb, true);
4202        check_indent_newline(dl);
4203        print_uint(PRINT_ANY, "sb", "sb %u",
4204                   mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
4205        print_uint(PRINT_ANY, "pool", " pool %u",
4206                   mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]));
4207        print_uint(PRINT_ANY, "threshold", " threshold %u",
4208                   mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD]));
4209        pr_out_port_handle_end(dl);
4210}
4211
4212static int cmd_sb_port_pool_show_cb(const struct nlmsghdr *nlh, void *data)
4213{
4214        struct dl *dl = data;
4215        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4216        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4217
4218        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4219        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4220            !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
4221            !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD])
4222                return MNL_CB_ERROR;
4223        pr_out_sb_port_pool(dl, tb);
4224        return MNL_CB_OK;
4225}
4226
4227static int cmd_sb_port_pool_show(struct dl *dl)
4228{
4229        struct nlmsghdr *nlh;
4230        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
4231        int err;
4232
4233        if (dl_argc(dl) == 0)
4234                flags |= NLM_F_DUMP;
4235
4236        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags);
4237
4238        if (dl_argc(dl) > 0) {
4239                err = dl_argv_parse_put(nlh, dl,
4240                                        DL_OPT_HANDLEP | DL_OPT_SB_POOL,
4241                                        DL_OPT_SB);
4242                if (err)
4243                        return err;
4244        }
4245
4246        pr_out_section_start(dl, "port_pool");
4247        err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_port_pool_show_cb, dl);
4248        pr_out_section_end(dl);
4249        return 0;
4250}
4251
4252static int cmd_sb_port_pool_set(struct dl *dl)
4253{
4254        struct nlmsghdr *nlh;
4255        int err;
4256
4257        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_SET,
4258                               NLM_F_REQUEST | NLM_F_ACK);
4259
4260        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_POOL |
4261                                DL_OPT_SB_TH, DL_OPT_SB);
4262        if (err)
4263                return err;
4264
4265        return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
4266}
4267
4268static int cmd_sb_port_pool(struct dl *dl)
4269{
4270        if (dl_argv_match(dl, "help")) {
4271                cmd_sb_help();
4272                return 0;
4273        } else if (dl_argv_match(dl, "show") ||
4274                   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
4275                dl_arg_inc(dl);
4276                return cmd_sb_port_pool_show(dl);
4277        } else if (dl_argv_match(dl, "set")) {
4278                dl_arg_inc(dl);
4279                return cmd_sb_port_pool_set(dl);
4280        }
4281        pr_err("Command \"%s\" not found\n", dl_argv(dl));
4282        return -ENOENT;
4283}
4284
4285static int cmd_sb_port(struct dl *dl)
4286{
4287        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
4288                cmd_sb_help();
4289                return 0;
4290        } else if (dl_argv_match(dl, "pool")) {
4291                dl_arg_inc(dl);
4292                return cmd_sb_port_pool(dl);
4293        }
4294        pr_err("Command \"%s\" not found\n", dl_argv(dl));
4295        return -ENOENT;
4296}
4297
4298static void pr_out_sb_tc_bind(struct dl *dl, struct nlattr **tb)
4299{
4300        pr_out_port_handle_start_arr(dl, tb, true);
4301        check_indent_newline(dl);
4302        print_uint(PRINT_ANY, "sb", "sb %u",
4303                   mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
4304        print_uint(PRINT_ANY, "tc", " tc %u",
4305                   mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]));
4306        print_string(PRINT_ANY, "type", " type %s",
4307                     pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])));
4308        print_uint(PRINT_ANY, "pool", " pool %u",
4309                   mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]));
4310        print_uint(PRINT_ANY, "threshold", " threshold %u",
4311                   mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD]));
4312        pr_out_port_handle_end(dl);
4313}
4314
4315static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr *nlh, void *data)
4316{
4317        struct dl *dl = data;
4318        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4319        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4320
4321        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4322        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4323            !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
4324            !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] ||
4325            !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD])
4326                return MNL_CB_ERROR;
4327        pr_out_sb_tc_bind(dl, tb);
4328        return MNL_CB_OK;
4329}
4330
4331static int cmd_sb_tc_bind_show(struct dl *dl)
4332{
4333        struct nlmsghdr *nlh;
4334        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
4335        int err;
4336
4337        if (dl_argc(dl) == 0)
4338                flags |= NLM_F_DUMP;
4339
4340        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags);
4341
4342        if (dl_argc(dl) > 0) {
4343                err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC |
4344                                        DL_OPT_SB_TYPE, DL_OPT_SB);
4345                if (err)
4346                        return err;
4347        }
4348
4349        pr_out_section_start(dl, "tc_bind");
4350        err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_tc_bind_show_cb, dl);
4351        pr_out_section_end(dl);
4352        return err;
4353}
4354
4355static int cmd_sb_tc_bind_set(struct dl *dl)
4356{
4357        struct nlmsghdr *nlh;
4358        int err;
4359
4360        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_SET,
4361                               NLM_F_REQUEST | NLM_F_ACK);
4362
4363        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC |
4364                                DL_OPT_SB_TYPE | DL_OPT_SB_POOL | DL_OPT_SB_TH,
4365                                DL_OPT_SB);
4366        if (err)
4367                return err;
4368
4369        return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
4370}
4371
4372static int cmd_sb_tc_bind(struct dl *dl)
4373{
4374        if (dl_argv_match(dl, "help")) {
4375                cmd_sb_help();
4376                return 0;
4377        } else if (dl_argv_match(dl, "show") ||
4378                   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
4379                dl_arg_inc(dl);
4380                return cmd_sb_tc_bind_show(dl);
4381        } else if (dl_argv_match(dl, "set")) {
4382                dl_arg_inc(dl);
4383                return cmd_sb_tc_bind_set(dl);
4384        }
4385        pr_err("Command \"%s\" not found\n", dl_argv(dl));
4386        return -ENOENT;
4387}
4388
4389static int cmd_sb_tc(struct dl *dl)
4390{
4391        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
4392                cmd_sb_help();
4393                return 0;
4394        } else if (dl_argv_match(dl, "bind")) {
4395                dl_arg_inc(dl);
4396                return cmd_sb_tc_bind(dl);
4397        }
4398        pr_err("Command \"%s\" not found\n", dl_argv(dl));
4399        return -ENOENT;
4400}
4401
4402struct occ_item {
4403        struct list_head list;
4404        uint32_t index;
4405        uint32_t cur;
4406        uint32_t max;
4407        uint32_t bound_pool_index;
4408};
4409
4410struct occ_port {
4411        struct list_head list;
4412        char *bus_name;
4413        char *dev_name;
4414        uint32_t port_index;
4415        uint32_t sb_index;
4416        struct list_head pool_list;
4417        struct list_head ing_tc_list;
4418        struct list_head eg_tc_list;
4419};
4420
4421struct occ_show {
4422        struct dl *dl;
4423        int err;
4424        struct list_head port_list;
4425};
4426
4427static struct occ_item *occ_item_alloc(void)
4428{
4429        return calloc(1, sizeof(struct occ_item));
4430}
4431
4432static void occ_item_free(struct occ_item *occ_item)
4433{
4434        free(occ_item);
4435}
4436
4437static struct occ_port *occ_port_alloc(uint32_t port_index)
4438{
4439        struct occ_port *occ_port;
4440
4441        occ_port = calloc(1, sizeof(*occ_port));
4442        if (!occ_port)
4443                return NULL;
4444        occ_port->port_index = port_index;
4445        INIT_LIST_HEAD(&occ_port->pool_list);
4446        INIT_LIST_HEAD(&occ_port->ing_tc_list);
4447        INIT_LIST_HEAD(&occ_port->eg_tc_list);
4448        return occ_port;
4449}
4450
4451static void occ_port_free(struct occ_port *occ_port)
4452{
4453        struct occ_item *occ_item, *tmp;
4454
4455        list_for_each_entry_safe(occ_item, tmp, &occ_port->pool_list, list)
4456                occ_item_free(occ_item);
4457        list_for_each_entry_safe(occ_item, tmp, &occ_port->ing_tc_list, list)
4458                occ_item_free(occ_item);
4459        list_for_each_entry_safe(occ_item, tmp, &occ_port->eg_tc_list, list)
4460                occ_item_free(occ_item);
4461}
4462
4463static struct occ_show *occ_show_alloc(struct dl *dl)
4464{
4465        struct occ_show *occ_show;
4466
4467        occ_show = calloc(1, sizeof(*occ_show));
4468        if (!occ_show)
4469                return NULL;
4470        occ_show->dl = dl;
4471        INIT_LIST_HEAD(&occ_show->port_list);
4472        return occ_show;
4473}
4474
4475static void occ_show_free(struct occ_show *occ_show)
4476{
4477        struct occ_port *occ_port, *tmp;
4478
4479        list_for_each_entry_safe(occ_port, tmp, &occ_show->port_list, list)
4480                occ_port_free(occ_port);
4481}
4482
4483static struct occ_port *occ_port_get(struct occ_show *occ_show,
4484                                     struct nlattr **tb)
4485{
4486        struct occ_port *occ_port;
4487        uint32_t port_index;
4488
4489        port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]);
4490
4491        list_for_each_entry_reverse(occ_port, &occ_show->port_list, list) {
4492                if (occ_port->port_index == port_index)
4493                        return occ_port;
4494        }
4495        occ_port = occ_port_alloc(port_index);
4496        if (!occ_port)
4497                return NULL;
4498        list_add_tail(&occ_port->list, &occ_show->port_list);
4499        return occ_port;
4500}
4501
4502static void pr_out_occ_show_item_list(const char *label, struct list_head *list,
4503                                      bool bound_pool)
4504{
4505        struct occ_item *occ_item;
4506        int i = 1;
4507
4508        pr_out_sp(7, "  %s:", label);
4509        list_for_each_entry(occ_item, list, list) {
4510                if ((i - 1) % 4 == 0 && i != 1)
4511                        pr_out_sp(7, " ");
4512                if (bound_pool)
4513                        pr_out_sp(7, "%2u(%u):", occ_item->index,
4514                                  occ_item->bound_pool_index);
4515                else
4516                        pr_out_sp(7, "%2u:", occ_item->index);
4517                pr_out_sp(21, "%10u/%u", occ_item->cur, occ_item->max);
4518                if (i++ % 4 == 0)
4519                        pr_out("\n");
4520        }
4521        if ((i - 1) % 4 != 0)
4522                pr_out("\n");
4523}
4524
4525static void pr_out_json_occ_show_item_list(struct dl *dl, const char *label,
4526                                           struct list_head *list,
4527                                           bool bound_pool)
4528{
4529        struct occ_item *occ_item;
4530        char buf[32];
4531
4532        open_json_object(label);
4533        list_for_each_entry(occ_item, list, list) {
4534                sprintf(buf, "%u", occ_item->index);
4535                open_json_object(buf);
4536                if (bound_pool)
4537                        print_uint(PRINT_JSON, "bound_pool", NULL,
4538                                   occ_item->bound_pool_index);
4539                print_uint(PRINT_JSON, "current", NULL, occ_item->cur);
4540                print_uint(PRINT_JSON, "max", NULL, occ_item->max);
4541                close_json_object();
4542        }
4543        close_json_object();
4544}
4545
4546static void pr_out_occ_show_port(struct dl *dl, struct occ_port *occ_port)
4547{
4548        if (dl->json_output) {
4549                pr_out_json_occ_show_item_list(dl, "pool",
4550                                               &occ_port->pool_list, false);
4551                pr_out_json_occ_show_item_list(dl, "itc",
4552                                               &occ_port->ing_tc_list, true);
4553                pr_out_json_occ_show_item_list(dl, "etc",
4554                                               &occ_port->eg_tc_list, true);
4555        } else {
4556                pr_out("\n");
4557                pr_out_occ_show_item_list("pool", &occ_port->pool_list, false);
4558                pr_out_occ_show_item_list("itc", &occ_port->ing_tc_list, true);
4559                pr_out_occ_show_item_list("etc", &occ_port->eg_tc_list, true);
4560        }
4561}
4562
4563static void pr_out_occ_show(struct occ_show *occ_show)
4564{
4565        struct dl *dl = occ_show->dl;
4566        struct dl_opts *opts = &dl->opts;
4567        struct occ_port *occ_port;
4568
4569        list_for_each_entry(occ_port, &occ_show->port_list, list) {
4570                __pr_out_port_handle_start(dl, opts->bus_name, opts->dev_name,
4571                                           occ_port->port_index, true, false);
4572                pr_out_occ_show_port(dl, occ_port);
4573                pr_out_port_handle_end(dl);
4574        }
4575}
4576
4577static void cmd_sb_occ_port_pool_process(struct occ_show *occ_show,
4578                                         struct nlattr **tb)
4579{
4580        struct occ_port *occ_port;
4581        struct occ_item *occ_item;
4582
4583        if (occ_show->err || !dl_dump_filter(occ_show->dl, tb))
4584                return;
4585
4586        occ_port = occ_port_get(occ_show, tb);
4587        if (!occ_port) {
4588                occ_show->err = -ENOMEM;
4589                return;
4590        }
4591
4592        occ_item = occ_item_alloc();
4593        if (!occ_item) {
4594                occ_show->err = -ENOMEM;
4595                return;
4596        }
4597        occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]);
4598        occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]);
4599        occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]);
4600        list_add_tail(&occ_item->list, &occ_port->pool_list);
4601}
4602
4603static int cmd_sb_occ_port_pool_process_cb(const struct nlmsghdr *nlh, void *data)
4604{
4605        struct occ_show *occ_show = data;
4606        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4607        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4608
4609        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4610        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4611            !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
4612            !tb[DEVLINK_ATTR_SB_POOL_INDEX] ||
4613            !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX])
4614                return MNL_CB_ERROR;
4615        cmd_sb_occ_port_pool_process(occ_show, tb);
4616        return MNL_CB_OK;
4617}
4618
4619static void cmd_sb_occ_tc_pool_process(struct occ_show *occ_show,
4620                                       struct nlattr **tb)
4621{
4622        struct occ_port *occ_port;
4623        struct occ_item *occ_item;
4624        uint8_t pool_type;
4625
4626        if (occ_show->err || !dl_dump_filter(occ_show->dl, tb))
4627                return;
4628
4629        occ_port = occ_port_get(occ_show, tb);
4630        if (!occ_port) {
4631                occ_show->err = -ENOMEM;
4632                return;
4633        }
4634
4635        occ_item = occ_item_alloc();
4636        if (!occ_item) {
4637                occ_show->err = -ENOMEM;
4638                return;
4639        }
4640        occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]);
4641        occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]);
4642        occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]);
4643        occ_item->bound_pool_index =
4644                        mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]);
4645        pool_type = mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE]);
4646        if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS)
4647                list_add_tail(&occ_item->list, &occ_port->ing_tc_list);
4648        else if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS)
4649                list_add_tail(&occ_item->list, &occ_port->eg_tc_list);
4650        else
4651                occ_item_free(occ_item);
4652}
4653
4654static int cmd_sb_occ_tc_pool_process_cb(const struct nlmsghdr *nlh, void *data)
4655{
4656        struct occ_show *occ_show = data;
4657        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4658        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4659
4660        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4661        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4662            !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
4663            !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] ||
4664            !tb[DEVLINK_ATTR_SB_POOL_INDEX] ||
4665            !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX])
4666                return MNL_CB_ERROR;
4667        cmd_sb_occ_tc_pool_process(occ_show, tb);
4668        return MNL_CB_OK;
4669}
4670
4671static int cmd_sb_occ_show(struct dl *dl)
4672{
4673        struct nlmsghdr *nlh;
4674        struct occ_show *occ_show;
4675        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP;
4676        int err;
4677
4678        err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_HANDLEP, DL_OPT_SB);
4679        if (err)
4680                return err;
4681
4682        occ_show = occ_show_alloc(dl);
4683        if (!occ_show)
4684                return -ENOMEM;
4685
4686        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags);
4687
4688        err = _mnlg_socket_sndrcv(dl->nlg, nlh,
4689                                  cmd_sb_occ_port_pool_process_cb, occ_show);
4690        if (err)
4691                goto out;
4692
4693        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags);
4694
4695        err = _mnlg_socket_sndrcv(dl->nlg, nlh,
4696                                  cmd_sb_occ_tc_pool_process_cb, occ_show);
4697        if (err)
4698                goto out;
4699
4700        pr_out_section_start(dl, "occupancy");
4701        pr_out_occ_show(occ_show);
4702        pr_out_section_end(dl);
4703
4704out:
4705        occ_show_free(occ_show);
4706        return err;
4707}
4708
4709static int cmd_sb_occ_snapshot(struct dl *dl)
4710{
4711        struct nlmsghdr *nlh;
4712        int err;
4713
4714        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_SNAPSHOT,
4715                               NLM_F_REQUEST | NLM_F_ACK);
4716
4717        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB);
4718        if (err)
4719                return err;
4720
4721        return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
4722}
4723
4724static int cmd_sb_occ_clearmax(struct dl *dl)
4725{
4726        struct nlmsghdr *nlh;
4727        int err;
4728
4729        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_MAX_CLEAR,
4730                               NLM_F_REQUEST | NLM_F_ACK);
4731
4732        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB);
4733        if (err)
4734                return err;
4735
4736        return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
4737}
4738
4739static int cmd_sb_occ(struct dl *dl)
4740{
4741        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
4742                cmd_sb_help();
4743                return 0;
4744        } else if (dl_argv_match(dl, "show") ||
4745                   dl_argv_match(dl, "list")) {
4746                dl_arg_inc(dl);
4747                return cmd_sb_occ_show(dl);
4748        } else if (dl_argv_match(dl, "snapshot")) {
4749                dl_arg_inc(dl);
4750                return cmd_sb_occ_snapshot(dl);
4751        } else if (dl_argv_match(dl, "clearmax")) {
4752                dl_arg_inc(dl);
4753                return cmd_sb_occ_clearmax(dl);
4754        }
4755        pr_err("Command \"%s\" not found\n", dl_argv(dl));
4756        return -ENOENT;
4757}
4758
4759static int cmd_sb(struct dl *dl)
4760{
4761        if (dl_argv_match(dl, "help")) {
4762                cmd_sb_help();
4763                return 0;
4764        } else if (dl_argv_match(dl, "show") ||
4765                   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
4766                dl_arg_inc(dl);
4767                return cmd_sb_show(dl);
4768        } else if (dl_argv_match(dl, "pool")) {
4769                dl_arg_inc(dl);
4770                return cmd_sb_pool(dl);
4771        } else if (dl_argv_match(dl, "port")) {
4772                dl_arg_inc(dl);
4773                return cmd_sb_port(dl);
4774        } else if (dl_argv_match(dl, "tc")) {
4775                dl_arg_inc(dl);
4776                return cmd_sb_tc(dl);
4777        } else if (dl_argv_match(dl, "occupancy")) {
4778                dl_arg_inc(dl);
4779                return cmd_sb_occ(dl);
4780        }
4781        pr_err("Command \"%s\" not found\n", dl_argv(dl));
4782        return -ENOENT;
4783}
4784
4785static const char *cmd_name(uint8_t cmd)
4786{
4787        switch (cmd) {
4788        case DEVLINK_CMD_UNSPEC: return "unspec";
4789        case DEVLINK_CMD_GET: return "get";
4790        case DEVLINK_CMD_SET: return "set";
4791        case DEVLINK_CMD_NEW: return "new";
4792        case DEVLINK_CMD_DEL: return "del";
4793        case DEVLINK_CMD_PORT_GET: return "get";
4794        case DEVLINK_CMD_PORT_SET: return "set";
4795        case DEVLINK_CMD_PORT_NEW: return "new";
4796        case DEVLINK_CMD_PORT_DEL: return "del";
4797        case DEVLINK_CMD_PARAM_GET: return "get";
4798        case DEVLINK_CMD_PARAM_SET: return "set";
4799        case DEVLINK_CMD_PARAM_NEW: return "new";
4800        case DEVLINK_CMD_PARAM_DEL: return "del";
4801        case DEVLINK_CMD_REGION_GET: return "get";
4802        case DEVLINK_CMD_REGION_SET: return "set";
4803        case DEVLINK_CMD_REGION_NEW: return "new";
4804        case DEVLINK_CMD_REGION_DEL: return "del";
4805        case DEVLINK_CMD_FLASH_UPDATE: return "begin";
4806        case DEVLINK_CMD_FLASH_UPDATE_END: return "end";
4807        case DEVLINK_CMD_FLASH_UPDATE_STATUS: return "status";
4808        case DEVLINK_CMD_HEALTH_REPORTER_RECOVER: return "status";
4809        case DEVLINK_CMD_TRAP_GET: return "get";
4810        case DEVLINK_CMD_TRAP_SET: return "set";
4811        case DEVLINK_CMD_TRAP_NEW: return "new";
4812        case DEVLINK_CMD_TRAP_DEL: return "del";
4813        case DEVLINK_CMD_TRAP_GROUP_GET: return "get";
4814        case DEVLINK_CMD_TRAP_GROUP_SET: return "set";
4815        case DEVLINK_CMD_TRAP_GROUP_NEW: return "new";
4816        case DEVLINK_CMD_TRAP_GROUP_DEL: return "del";
4817        case DEVLINK_CMD_TRAP_POLICER_GET: return "get";
4818        case DEVLINK_CMD_TRAP_POLICER_SET: return "set";
4819        case DEVLINK_CMD_TRAP_POLICER_NEW: return "new";
4820        case DEVLINK_CMD_TRAP_POLICER_DEL: return "del";
4821        default: return "<unknown cmd>";
4822        }
4823}
4824
4825static const char *cmd_obj(uint8_t cmd)
4826{
4827        switch (cmd) {
4828        case DEVLINK_CMD_UNSPEC: return "unspec";
4829        case DEVLINK_CMD_GET:
4830        case DEVLINK_CMD_SET:
4831        case DEVLINK_CMD_NEW:
4832        case DEVLINK_CMD_DEL:
4833                return "dev";
4834        case DEVLINK_CMD_PORT_GET:
4835        case DEVLINK_CMD_PORT_SET:
4836        case DEVLINK_CMD_PORT_NEW:
4837        case DEVLINK_CMD_PORT_DEL:
4838                return "port";
4839        case DEVLINK_CMD_PARAM_GET:
4840        case DEVLINK_CMD_PARAM_SET:
4841        case DEVLINK_CMD_PARAM_NEW:
4842        case DEVLINK_CMD_PARAM_DEL:
4843                return "param";
4844        case DEVLINK_CMD_REGION_GET:
4845        case DEVLINK_CMD_REGION_SET:
4846        case DEVLINK_CMD_REGION_NEW:
4847        case DEVLINK_CMD_REGION_DEL:
4848                return "region";
4849        case DEVLINK_CMD_FLASH_UPDATE:
4850        case DEVLINK_CMD_FLASH_UPDATE_END:
4851        case DEVLINK_CMD_FLASH_UPDATE_STATUS:
4852                return "flash";
4853        case DEVLINK_CMD_HEALTH_REPORTER_RECOVER:
4854                return "health";
4855        case DEVLINK_CMD_TRAP_GET:
4856        case DEVLINK_CMD_TRAP_SET:
4857        case DEVLINK_CMD_TRAP_NEW:
4858        case DEVLINK_CMD_TRAP_DEL:
4859                return "trap";
4860        case DEVLINK_CMD_TRAP_GROUP_GET:
4861        case DEVLINK_CMD_TRAP_GROUP_SET:
4862        case DEVLINK_CMD_TRAP_GROUP_NEW:
4863        case DEVLINK_CMD_TRAP_GROUP_DEL:
4864                return "trap-group";
4865        case DEVLINK_CMD_TRAP_POLICER_GET:
4866        case DEVLINK_CMD_TRAP_POLICER_SET:
4867        case DEVLINK_CMD_TRAP_POLICER_NEW:
4868        case DEVLINK_CMD_TRAP_POLICER_DEL:
4869                return "trap-policer";
4870        default: return "<unknown obj>";
4871        }
4872}
4873
4874static void pr_out_mon_header(uint8_t cmd)
4875{
4876        if (!is_json_context()) {
4877                pr_out("[%s,%s] ", cmd_obj(cmd), cmd_name(cmd));
4878        } else {
4879                open_json_object(NULL);
4880                print_string(PRINT_JSON, "command", NULL, cmd_name(cmd));
4881                open_json_object(cmd_obj(cmd));
4882        }
4883}
4884
4885static void pr_out_mon_footer(void)
4886{
4887        if (is_json_context()) {
4888                close_json_object();
4889                close_json_object();
4890        }
4891}
4892
4893static bool cmd_filter_check(struct dl *dl, uint8_t cmd)
4894{
4895        const char *obj = cmd_obj(cmd);
4896        unsigned int index = 0;
4897        const char *cur_obj;
4898
4899        if (dl_no_arg(dl))
4900                return true;
4901        while ((cur_obj = dl_argv_index(dl, index++))) {
4902                if (strcmp(cur_obj, obj) == 0 || strcmp(cur_obj, "all") == 0)
4903                        return true;
4904        }
4905        return false;
4906}
4907
4908static void pr_out_flash_update(struct dl *dl, struct nlattr **tb)
4909{
4910        __pr_out_handle_start(dl, tb, true, false);
4911
4912        if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG]) {
4913                check_indent_newline(dl);
4914                print_string(PRINT_ANY, "msg", "msg %s",
4915                             mnl_attr_get_str(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG]));
4916        }
4917        if (tb[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT]) {
4918                check_indent_newline(dl);
4919                print_string(PRINT_ANY, "component", "component %s",
4920                             mnl_attr_get_str(tb[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT]));
4921        }
4922
4923        if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE])
4924                pr_out_u64(dl, "done",
4925                           mnl_attr_get_u64(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE]));
4926
4927        if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL])
4928                pr_out_u64(dl, "total",
4929                           mnl_attr_get_u64(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL]));
4930
4931        pr_out_handle_end(dl);
4932}
4933
4934static void pr_out_region(struct dl *dl, struct nlattr **tb);
4935static void pr_out_health(struct dl *dl, struct nlattr **tb_health,
4936                          bool show_device, bool show_port);
4937static void pr_out_trap(struct dl *dl, struct nlattr **tb, bool array);
4938static void pr_out_trap_group(struct dl *dl, struct nlattr **tb, bool array);
4939static void pr_out_trap_policer(struct dl *dl, struct nlattr **tb, bool array);
4940
4941static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data)
4942{
4943        struct dl *dl = data;
4944        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4945        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4946        uint8_t cmd = genl->cmd;
4947
4948        if (!cmd_filter_check(dl, cmd))
4949                return MNL_CB_OK;
4950
4951        switch (cmd) {
4952        case DEVLINK_CMD_GET: /* fall through */
4953        case DEVLINK_CMD_SET: /* fall through */
4954        case DEVLINK_CMD_NEW: /* fall through */
4955        case DEVLINK_CMD_DEL:
4956                mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4957                if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
4958                        return MNL_CB_ERROR;
4959                pr_out_mon_header(genl->cmd);
4960                dl->stats = true;
4961                pr_out_dev(dl, tb);
4962                pr_out_mon_footer();
4963                break;
4964        case DEVLINK_CMD_PORT_GET: /* fall through */
4965        case DEVLINK_CMD_PORT_SET: /* fall through */
4966        case DEVLINK_CMD_PORT_NEW: /* fall through */
4967        case DEVLINK_CMD_PORT_DEL:
4968                mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4969                if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4970                    !tb[DEVLINK_ATTR_PORT_INDEX])
4971                        return MNL_CB_ERROR;
4972                pr_out_mon_header(genl->cmd);
4973                pr_out_port(dl, tb);
4974                pr_out_mon_footer();
4975                break;
4976        case DEVLINK_CMD_PARAM_GET: /* fall through */
4977        case DEVLINK_CMD_PARAM_SET: /* fall through */
4978        case DEVLINK_CMD_PARAM_NEW: /* fall through */
4979        case DEVLINK_CMD_PARAM_DEL:
4980                mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4981                if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4982                    !tb[DEVLINK_ATTR_PARAM])
4983                        return MNL_CB_ERROR;
4984                pr_out_mon_header(genl->cmd);
4985                pr_out_param(dl, tb, false);
4986                pr_out_mon_footer();
4987                break;
4988        case DEVLINK_CMD_REGION_GET: /* fall through */
4989        case DEVLINK_CMD_REGION_SET: /* fall through */
4990        case DEVLINK_CMD_REGION_NEW: /* fall through */
4991        case DEVLINK_CMD_REGION_DEL:
4992                mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4993                if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4994                    !tb[DEVLINK_ATTR_REGION_NAME])
4995                        return MNL_CB_ERROR;
4996                pr_out_mon_header(genl->cmd);
4997                pr_out_region(dl, tb);
4998                pr_out_mon_footer();
4999                break;
5000        case DEVLINK_CMD_FLASH_UPDATE: /* fall through */
5001        case DEVLINK_CMD_FLASH_UPDATE_END: /* fall through */
5002        case DEVLINK_CMD_FLASH_UPDATE_STATUS:
5003                mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5004                if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
5005                        return MNL_CB_ERROR;
5006                pr_out_mon_header(genl->cmd);
5007                pr_out_flash_update(dl, tb);
5008                pr_out_mon_footer();
5009                break;
5010        case DEVLINK_CMD_HEALTH_REPORTER_RECOVER:
5011                mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5012                if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5013                    !tb[DEVLINK_ATTR_HEALTH_REPORTER])
5014                        return MNL_CB_ERROR;
5015                pr_out_mon_header(genl->cmd);
5016                pr_out_health(dl, tb, true, true);
5017                pr_out_mon_footer();
5018                break;
5019        case DEVLINK_CMD_TRAP_GET: /* fall through */
5020        case DEVLINK_CMD_TRAP_SET: /* fall through */
5021        case DEVLINK_CMD_TRAP_NEW: /* fall through */
5022        case DEVLINK_CMD_TRAP_DEL:
5023                mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5024                if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5025                    !tb[DEVLINK_ATTR_TRAP_NAME] ||
5026                    !tb[DEVLINK_ATTR_TRAP_TYPE] ||
5027                    !tb[DEVLINK_ATTR_TRAP_ACTION] ||
5028                    !tb[DEVLINK_ATTR_TRAP_GROUP_NAME] ||
5029                    !tb[DEVLINK_ATTR_TRAP_METADATA] ||
5030                    !tb[DEVLINK_ATTR_STATS])
5031                        return MNL_CB_ERROR;
5032                pr_out_mon_header(genl->cmd);
5033                pr_out_trap(dl, tb, false);
5034                pr_out_mon_footer();
5035                break;
5036        case DEVLINK_CMD_TRAP_GROUP_GET: /* fall through */
5037        case DEVLINK_CMD_TRAP_GROUP_SET: /* fall through */
5038        case DEVLINK_CMD_TRAP_GROUP_NEW: /* fall through */
5039        case DEVLINK_CMD_TRAP_GROUP_DEL:
5040                mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5041                if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5042                    !tb[DEVLINK_ATTR_TRAP_GROUP_NAME] ||
5043                    !tb[DEVLINK_ATTR_STATS])
5044                        return MNL_CB_ERROR;
5045                pr_out_mon_header(genl->cmd);
5046                pr_out_trap_group(dl, tb, false);
5047                pr_out_mon_footer();
5048                break;
5049        case DEVLINK_CMD_TRAP_POLICER_GET: /* fall through */
5050        case DEVLINK_CMD_TRAP_POLICER_SET: /* fall through */
5051        case DEVLINK_CMD_TRAP_POLICER_NEW: /* fall through */
5052        case DEVLINK_CMD_TRAP_POLICER_DEL: /* fall through */
5053                mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5054                if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5055                    !tb[DEVLINK_ATTR_TRAP_POLICER_ID] ||
5056                    !tb[DEVLINK_ATTR_TRAP_POLICER_RATE] ||
5057                    !tb[DEVLINK_ATTR_TRAP_POLICER_BURST])
5058                        return MNL_CB_ERROR;
5059                pr_out_mon_header(genl->cmd);
5060                pr_out_trap_policer(dl, tb, false);
5061                break;
5062        }
5063        fflush(stdout);
5064        return MNL_CB_OK;
5065}
5066
5067static int cmd_mon_show(struct dl *dl)
5068{
5069        int err;
5070        unsigned int index = 0;
5071        const char *cur_obj;
5072
5073        while ((cur_obj = dl_argv_index(dl, index++))) {
5074                if (strcmp(cur_obj, "all") != 0 &&
5075                    strcmp(cur_obj, "dev") != 0 &&
5076                    strcmp(cur_obj, "port") != 0 &&
5077                    strcmp(cur_obj, "health") != 0 &&
5078                    strcmp(cur_obj, "trap") != 0 &&
5079                    strcmp(cur_obj, "trap-group") != 0 &&
5080                    strcmp(cur_obj, "trap-policer") != 0) {
5081                        pr_err("Unknown object \"%s\"\n", cur_obj);
5082                        return -EINVAL;
5083                }
5084        }
5085        err = _mnlg_socket_group_add(dl->nlg, DEVLINK_GENL_MCGRP_CONFIG_NAME);
5086        if (err)
5087                return err;
5088        open_json_object(NULL);
5089        open_json_array(PRINT_JSON, "mon");
5090        err = _mnlg_socket_recv_run_intr(dl->nlg, cmd_mon_show_cb, dl);
5091        close_json_array(PRINT_JSON, NULL);
5092        close_json_object();
5093        if (err)
5094                return err;
5095        return 0;
5096}
5097
5098static void cmd_mon_help(void)
5099{
5100        pr_err("Usage: devlink monitor [ all | OBJECT-LIST ]\n"
5101               "where  OBJECT-LIST := { dev | port | health | trap | trap-group | trap-policer }\n");
5102}
5103
5104static int cmd_mon(struct dl *dl)
5105{
5106        if (dl_argv_match(dl, "help")) {
5107                cmd_mon_help();
5108                return 0;
5109        }
5110        return cmd_mon_show(dl);
5111}
5112
5113struct dpipe_field {
5114        char *name;
5115        unsigned int id;
5116        unsigned int bitwidth;
5117        enum devlink_dpipe_field_mapping_type mapping_type;
5118};
5119
5120struct dpipe_header {
5121        struct list_head list;
5122        char *name;
5123        unsigned int id;
5124        struct dpipe_field *fields;
5125        unsigned int fields_count;
5126};
5127
5128struct dpipe_table {
5129        struct list_head list;
5130        char *name;
5131        unsigned int resource_id;
5132        bool resource_valid;
5133};
5134
5135struct dpipe_tables {
5136        struct list_head table_list;
5137};
5138
5139struct resource {
5140        char *name;
5141        uint64_t size;
5142        uint64_t size_new;
5143        uint64_t size_min;
5144        uint64_t size_max;
5145        uint64_t size_gran;
5146        enum devlink_resource_unit unit;
5147        bool size_valid;
5148        uint64_t size_occ;
5149        bool occ_valid;
5150        uint64_t id;
5151        struct list_head list;
5152        struct list_head resource_list;
5153        struct resource *parent;
5154};
5155
5156struct resources {
5157        struct list_head resource_list;
5158};
5159
5160struct resource_ctx {
5161        struct dl *dl;
5162        int err;
5163        struct resources *resources;
5164        struct dpipe_tables *tables;
5165        bool print_resources;
5166        bool pending_change;
5167};
5168
5169static struct resource *resource_alloc(void)
5170{
5171        struct resource *resource;
5172
5173        resource = calloc(1, sizeof(struct resource));
5174        if (!resource)
5175                return NULL;
5176        INIT_LIST_HEAD(&resource->resource_list);
5177        return resource;
5178}
5179
5180static void resource_free(struct resource *resource)
5181{
5182        struct resource *child_resource, *tmp;
5183
5184        list_for_each_entry_safe(child_resource, tmp, &resource->resource_list,
5185                                 list) {
5186                free(child_resource->name);
5187                resource_free(child_resource);
5188        }
5189        free(resource);
5190}
5191
5192static struct resources *resources_alloc(void)
5193{
5194        struct resources *resources;
5195
5196        resources = calloc(1, sizeof(struct resources));
5197        if (!resources)
5198                return NULL;
5199        INIT_LIST_HEAD(&resources->resource_list);
5200        return resources;
5201}
5202
5203static void resources_free(struct resources *resources)
5204{
5205        struct resource *resource, *tmp;
5206
5207        list_for_each_entry_safe(resource, tmp, &resources->resource_list, list)
5208                resource_free(resource);
5209}
5210
5211static int resource_ctx_init(struct resource_ctx *ctx, struct dl *dl)
5212{
5213        ctx->resources = resources_alloc();
5214        if (!ctx->resources)
5215                return -ENOMEM;
5216        ctx->dl = dl;
5217        return 0;
5218}
5219
5220static void resource_ctx_fini(struct resource_ctx *ctx)
5221{
5222        resources_free(ctx->resources);
5223}
5224
5225struct dpipe_ctx {
5226        struct dl *dl;
5227        int err;
5228        struct list_head global_headers;
5229        struct list_head local_headers;
5230        struct dpipe_tables *tables;
5231        struct resources *resources;
5232        bool print_headers;
5233        bool print_tables;
5234};
5235
5236static struct dpipe_header *dpipe_header_alloc(unsigned int fields_count)
5237{
5238        struct dpipe_header *header;
5239
5240        header = calloc(1, sizeof(struct dpipe_header));
5241        if (!header)
5242                return NULL;
5243        header->fields = calloc(fields_count, sizeof(struct dpipe_field));
5244        if (!header->fields)
5245                goto err_fields_alloc;
5246        header->fields_count = fields_count;
5247        return header;
5248
5249err_fields_alloc:
5250        free(header);
5251        return NULL;
5252}
5253
5254static void dpipe_header_free(struct dpipe_header *header)
5255{
5256        free(header->fields);
5257        free(header);
5258}
5259
5260static void dpipe_header_clear(struct dpipe_header *header)
5261{
5262        struct dpipe_field *field;
5263        int i;
5264
5265        for (i = 0; i < header->fields_count; i++) {
5266                field = &header->fields[i];
5267                free(field->name);
5268        }
5269        free(header->name);
5270}
5271
5272static void dpipe_header_add(struct dpipe_ctx *ctx,
5273                             struct dpipe_header *header, bool global)
5274{
5275        if (global)
5276                list_add(&header->list, &ctx->global_headers);
5277        else
5278                list_add(&header->list, &ctx->local_headers);
5279}
5280
5281static void dpipe_header_del(struct dpipe_header *header)
5282{
5283        list_del(&header->list);
5284}
5285
5286static struct dpipe_table *dpipe_table_alloc(void)
5287{
5288        return calloc(1, sizeof(struct dpipe_table));
5289}
5290
5291static void dpipe_table_free(struct dpipe_table *table)
5292{
5293        free(table);
5294}
5295
5296static struct dpipe_tables *dpipe_tables_alloc(void)
5297{
5298        struct dpipe_tables *tables;
5299
5300        tables = calloc(1, sizeof(struct dpipe_tables));
5301        if (!tables)
5302                return NULL;
5303        INIT_LIST_HEAD(&tables->table_list);
5304        return tables;
5305}
5306
5307static void dpipe_tables_free(struct dpipe_tables *tables)
5308{
5309        struct dpipe_table *table, *tmp;
5310
5311        list_for_each_entry_safe(table, tmp, &tables->table_list, list)
5312                dpipe_table_free(table);
5313        free(tables);
5314}
5315
5316static int dpipe_ctx_init(struct dpipe_ctx *ctx, struct dl *dl)
5317{
5318        ctx->tables = dpipe_tables_alloc();
5319        if (!ctx->tables)
5320                return -ENOMEM;
5321
5322        ctx->dl = dl;
5323        INIT_LIST_HEAD(&ctx->global_headers);
5324        INIT_LIST_HEAD(&ctx->local_headers);
5325        return 0;
5326}
5327
5328static void dpipe_ctx_fini(struct dpipe_ctx *ctx)
5329{
5330        struct dpipe_header *header, *tmp;
5331
5332        list_for_each_entry_safe(header, tmp, &ctx->global_headers,
5333                                 list) {
5334                dpipe_header_del(header);
5335                dpipe_header_clear(header);
5336                dpipe_header_free(header);
5337        }
5338        list_for_each_entry_safe(header, tmp, &ctx->local_headers,
5339                                 list) {
5340                dpipe_header_del(header);
5341                dpipe_header_clear(header);
5342                dpipe_header_free(header);
5343        }
5344        dpipe_tables_free(ctx->tables);
5345}
5346
5347static const char *dpipe_header_id2s(struct dpipe_ctx *ctx,
5348                                     uint32_t header_id, bool global)
5349{
5350        struct list_head *header_list;
5351        struct dpipe_header *header;
5352
5353        if (global)
5354                header_list = &ctx->global_headers;
5355        else
5356                header_list = &ctx->local_headers;
5357        list_for_each_entry(header, header_list, list) {
5358                if (header->id != header_id)
5359                        continue;
5360                return header->name;
5361        }
5362        return NULL;
5363}
5364
5365static const char *dpipe_field_id2s(struct dpipe_ctx *ctx,
5366                                    uint32_t header_id,
5367                                    uint32_t field_id, bool global)
5368{
5369        struct list_head *header_list;
5370        struct dpipe_header *header;
5371
5372        if (global)
5373                header_list = &ctx->global_headers;
5374        else
5375                header_list = &ctx->local_headers;
5376        list_for_each_entry(header, header_list, list) {
5377                if (header->id != header_id)
5378                        continue;
5379                return header->fields[field_id].name;
5380        }
5381        return NULL;
5382}
5383
5384static const char *
5385dpipe_field_mapping_e2s(enum devlink_dpipe_field_mapping_type mapping_type)
5386{
5387        switch (mapping_type) {
5388        case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_NONE:
5389                return NULL;
5390        case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX:
5391                return "ifindex";
5392        default:
5393                return "<unknown>";
5394        }
5395}
5396
5397static const char *
5398dpipe_mapping_get(struct dpipe_ctx *ctx, uint32_t header_id,
5399                  uint32_t field_id, bool global)
5400{
5401        enum devlink_dpipe_field_mapping_type mapping_type;
5402        struct list_head *header_list;
5403        struct dpipe_header *header;
5404
5405        if (global)
5406                header_list = &ctx->global_headers;
5407        else
5408                header_list = &ctx->local_headers;
5409        list_for_each_entry(header, header_list, list) {
5410                if (header->id != header_id)
5411                        continue;
5412                mapping_type = header->fields[field_id].mapping_type;
5413                return dpipe_field_mapping_e2s(mapping_type);
5414        }
5415        return NULL;
5416}
5417
5418static void pr_out_dpipe_fields(struct dpipe_ctx *ctx,
5419                                struct dpipe_field *fields,
5420                                unsigned int field_count)
5421{
5422        struct dpipe_field *field;
5423        int i;
5424
5425        for (i = 0; i < field_count; i++) {
5426                field = &fields[i];
5427                pr_out_entry_start(ctx->dl);
5428                check_indent_newline(ctx->dl);
5429                print_string(PRINT_ANY, "name", "name %s", field->name);
5430                if (ctx->dl->verbose)
5431                        print_uint(PRINT_ANY, "id", " id %u", field->id);
5432                print_uint(PRINT_ANY, "bitwidth", " bitwidth %u", field->bitwidth);
5433                if (field->mapping_type) {
5434                        print_string(PRINT_ANY, "mapping_type", " mapping_type %s",
5435                                     dpipe_field_mapping_e2s(field->mapping_type));
5436                }
5437                pr_out_entry_end(ctx->dl);
5438        }
5439}
5440
5441static void
5442pr_out_dpipe_header(struct dpipe_ctx *ctx, struct nlattr **tb,
5443                    struct dpipe_header *header, bool global)
5444{
5445        pr_out_handle_start_arr(ctx->dl, tb);
5446        check_indent_newline(ctx->dl);
5447        print_string(PRINT_ANY, "name", "name %s", header->name);
5448        if (ctx->dl->verbose) {
5449                print_uint(PRINT_ANY, "id", " id %u", header->id);
5450                print_bool(PRINT_ANY, "global", " global %s", global);
5451        }
5452        pr_out_array_start(ctx->dl, "field");
5453        pr_out_dpipe_fields(ctx, header->fields,
5454                            header->fields_count);
5455        pr_out_array_end(ctx->dl);
5456        pr_out_handle_end(ctx->dl);
5457}
5458
5459static void pr_out_dpipe_headers(struct dpipe_ctx *ctx,
5460                                 struct nlattr **tb)
5461{
5462        struct dpipe_header *header;
5463
5464        list_for_each_entry(header, &ctx->local_headers, list)
5465                pr_out_dpipe_header(ctx, tb, header, false);
5466
5467        list_for_each_entry(header, &ctx->global_headers, list)
5468                pr_out_dpipe_header(ctx, tb, header, true);
5469}
5470
5471static int dpipe_header_field_get(struct nlattr *nl, struct dpipe_field *field)
5472{
5473        struct nlattr *nla_field[DEVLINK_ATTR_MAX + 1] = {};
5474        const char *name;
5475        int err;
5476
5477        err = mnl_attr_parse_nested(nl, attr_cb, nla_field);
5478        if (err != MNL_CB_OK)
5479                return -EINVAL;
5480        if (!nla_field[DEVLINK_ATTR_DPIPE_FIELD_ID] ||
5481            !nla_field[DEVLINK_ATTR_DPIPE_FIELD_NAME] ||
5482            !nla_field[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH] ||
5483            !nla_field[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE])
5484                return -EINVAL;
5485
5486        name = mnl_attr_get_str(nla_field[DEVLINK_ATTR_DPIPE_FIELD_NAME]);
5487        field->id = mnl_attr_get_u32(nla_field[DEVLINK_ATTR_DPIPE_FIELD_ID]);
5488        field->bitwidth = mnl_attr_get_u32(nla_field[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH]);
5489        field->name = strdup(name);
5490        if (!field->name)
5491                return -ENOMEM;
5492        field->mapping_type = mnl_attr_get_u32(nla_field[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE]);
5493        return 0;
5494}
5495
5496static int dpipe_header_fields_get(struct nlattr *nla_fields,
5497                                   struct dpipe_field *fields)
5498{
5499        struct nlattr *nla_field;
5500        int count = 0;
5501        int err;
5502
5503        mnl_attr_for_each_nested(nla_field, nla_fields) {
5504                err = dpipe_header_field_get(nla_field, &fields[count]);
5505                if (err)
5506                        return err;
5507                count++;
5508        }
5509        return 0;
5510}
5511
5512static unsigned int dpipe_header_field_count_get(struct nlattr *nla_fields)
5513{
5514        struct nlattr *nla_field;
5515        unsigned int count = 0;
5516
5517        mnl_attr_for_each_nested(nla_field, nla_fields)
5518                count++;
5519        return count;
5520}
5521
5522static int dpipe_header_get(struct dpipe_ctx *ctx, struct nlattr *nl)
5523{
5524        struct nlattr *nla_header[DEVLINK_ATTR_MAX + 1] = {};
5525        struct dpipe_header *header;
5526        unsigned int fields_count;
5527        const char *header_name;
5528        bool global;
5529        int err;
5530
5531        err = mnl_attr_parse_nested(nl, attr_cb, nla_header);
5532        if (err != MNL_CB_OK)
5533                return -EINVAL;
5534
5535        if (!nla_header[DEVLINK_ATTR_DPIPE_HEADER_NAME] ||
5536            !nla_header[DEVLINK_ATTR_DPIPE_HEADER_ID] ||
5537            !nla_header[DEVLINK_ATTR_DPIPE_HEADER_FIELDS])
5538                return -EINVAL;
5539
5540        fields_count = dpipe_header_field_count_get(nla_header[DEVLINK_ATTR_DPIPE_HEADER_FIELDS]);
5541        header = dpipe_header_alloc(fields_count);
5542        if (!header)
5543                return -ENOMEM;
5544
5545        header_name = mnl_attr_get_str(nla_header[DEVLINK_ATTR_DPIPE_HEADER_NAME]);
5546        header->name = strdup(header_name);
5547        header->id = mnl_attr_get_u32(nla_header[DEVLINK_ATTR_DPIPE_HEADER_ID]);
5548        header->fields_count = fields_count;
5549        global = !!mnl_attr_get_u8(nla_header[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL]);
5550
5551        err = dpipe_header_fields_get(nla_header[DEVLINK_ATTR_DPIPE_HEADER_FIELDS],
5552                                      header->fields);
5553        if (err)
5554                goto err_field_get;
5555        dpipe_header_add(ctx, header, global);
5556        return 0;
5557
5558err_field_get:
5559        dpipe_header_free(header);
5560        return err;
5561}
5562
5563static int dpipe_headers_get(struct dpipe_ctx *ctx, struct nlattr **tb)
5564{
5565        struct nlattr *nla_headers = tb[DEVLINK_ATTR_DPIPE_HEADERS];
5566        struct nlattr *nla_header;
5567        int err;
5568
5569        mnl_attr_for_each_nested(nla_header, nla_headers) {
5570                err = dpipe_header_get(ctx, nla_header);
5571                if (err)
5572                        return err;
5573        }
5574        return 0;
5575}
5576
5577static int cmd_dpipe_header_cb(const struct nlmsghdr *nlh, void *data)
5578{
5579        struct dpipe_ctx *ctx = data;
5580        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
5581        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
5582        int err;
5583
5584        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5585        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5586            !tb[DEVLINK_ATTR_DPIPE_HEADERS])
5587                return MNL_CB_ERROR;
5588        err = dpipe_headers_get(ctx, tb);
5589        if (err) {
5590                ctx->err = err;
5591                return MNL_CB_ERROR;
5592        }
5593
5594        if (ctx->print_headers)
5595                pr_out_dpipe_headers(ctx, tb);
5596        return MNL_CB_OK;
5597}
5598
5599static int cmd_dpipe_headers_show(struct dl *dl)
5600{
5601        struct nlmsghdr *nlh;
5602        struct dpipe_ctx ctx = {};
5603        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
5604        int err;
5605
5606        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags);
5607
5608        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
5609        if (err)
5610                return err;
5611
5612        err = dpipe_ctx_init(&ctx, dl);
5613        if (err)
5614                return err;
5615
5616        ctx.print_headers = true;
5617
5618        pr_out_section_start(dl, "header");
5619        err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_header_cb, &ctx);
5620        if (err)
5621                pr_err("error get headers %s\n", strerror(ctx.err));
5622        pr_out_section_end(dl);
5623
5624        dpipe_ctx_fini(&ctx);
5625        return err;
5626}
5627
5628static void cmd_dpipe_help(void)
5629{
5630        pr_err("Usage: devlink dpipe table show DEV [ name TABLE_NAME ]\n");
5631        pr_err("       devlink dpipe table set DEV name TABLE_NAME\n");
5632        pr_err("                               [ counters_enabled { true | false } ]\n");
5633        pr_err("       devlink dpipe table dump DEV name TABLE_NAME\n");
5634        pr_err("       devlink dpipe header show DEV\n");
5635}
5636
5637static int cmd_dpipe_header(struct dl *dl)
5638{
5639        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
5640                cmd_dpipe_help();
5641                return 0;
5642        } else if (dl_argv_match(dl, "show")) {
5643                dl_arg_inc(dl);
5644                return cmd_dpipe_headers_show(dl);
5645        }
5646        pr_err("Command \"%s\" not found\n", dl_argv(dl));
5647        return -ENOENT;
5648}
5649
5650static const char
5651*dpipe_action_type_e2s(enum devlink_dpipe_action_type action_type)
5652{
5653        switch (action_type) {
5654        case DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY:
5655                return "field_modify";
5656        default:
5657                return "<unknown>";
5658        }
5659}
5660
5661struct dpipe_op_info {
5662        uint32_t header_id;
5663        uint32_t field_id;
5664        bool header_global;
5665};
5666
5667struct dpipe_action {
5668        struct dpipe_op_info info;
5669        uint32_t type;
5670};
5671
5672static void pr_out_dpipe_action(struct dpipe_action *action,
5673                                struct dpipe_ctx *ctx)
5674{
5675        struct dpipe_op_info *op_info = &action->info;
5676        const char *mapping;
5677
5678        check_indent_newline(ctx->dl);
5679        print_string(PRINT_ANY, "type", "type %s",
5680                     dpipe_action_type_e2s(action->type));
5681        print_string(PRINT_ANY, "header", " header %s",
5682                     dpipe_header_id2s(ctx, op_info->header_id,
5683                                       op_info->header_global));
5684        print_string(PRINT_ANY, "field", " field %s",
5685                     dpipe_field_id2s(ctx, op_info->header_id,
5686                                      op_info->field_id,
5687                                      op_info->header_global));
5688        mapping = dpipe_mapping_get(ctx, op_info->header_id,
5689                                    op_info->field_id,
5690                                    op_info->header_global);
5691        if (mapping)
5692                print_string(PRINT_ANY, "mapping", " mapping %s", mapping);
5693}
5694
5695static int dpipe_action_parse(struct dpipe_action *action, struct nlattr *nl)
5696{
5697        struct nlattr *nla_action[DEVLINK_ATTR_MAX + 1] = {};
5698        int err;
5699
5700        err = mnl_attr_parse_nested(nl, attr_cb, nla_action);
5701        if (err != MNL_CB_OK)
5702                return -EINVAL;
5703
5704        if (!nla_action[DEVLINK_ATTR_DPIPE_ACTION_TYPE] ||
5705            !nla_action[DEVLINK_ATTR_DPIPE_HEADER_INDEX] ||
5706            !nla_action[DEVLINK_ATTR_DPIPE_HEADER_ID] ||
5707            !nla_action[DEVLINK_ATTR_DPIPE_FIELD_ID]) {
5708                return -EINVAL;
5709        }
5710
5711        action->type = mnl_attr_get_u32(nla_action[DEVLINK_ATTR_DPIPE_ACTION_TYPE]);
5712        action->info.header_id = mnl_attr_get_u32(nla_action[DEVLINK_ATTR_DPIPE_HEADER_ID]);
5713        action->info.field_id = mnl_attr_get_u32(nla_action[DEVLINK_ATTR_DPIPE_FIELD_ID]);
5714        action->info.header_global = !!mnl_attr_get_u8(nla_action[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL]);
5715
5716        return 0;
5717}
5718
5719static int dpipe_table_actions_show(struct dpipe_ctx *ctx,
5720                                    struct nlattr *nla_actions)
5721{
5722        struct nlattr *nla_action;
5723        struct dpipe_action action;
5724
5725        mnl_attr_for_each_nested(nla_action, nla_actions) {
5726                pr_out_entry_start(ctx->dl);
5727                if (dpipe_action_parse(&action, nla_action))
5728                        goto err_action_parse;
5729                pr_out_dpipe_action(&action, ctx);
5730                pr_out_entry_end(ctx->dl);
5731        }
5732        return 0;
5733
5734err_action_parse:
5735        pr_out_entry_end(ctx->dl);
5736        return -EINVAL;
5737}
5738
5739static const char *
5740dpipe_match_type_e2s(enum devlink_dpipe_match_type match_type)
5741{
5742        switch (match_type) {
5743        case DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT:
5744                return "field_exact";
5745        default:
5746                return "<unknown>";
5747        }
5748}
5749
5750struct dpipe_match {
5751        struct dpipe_op_info info;
5752        uint32_t type;
5753};
5754
5755static void pr_out_dpipe_match(struct dpipe_match *match,
5756                               struct dpipe_ctx *ctx)
5757{
5758        struct dpipe_op_info *op_info = &match->info;
5759        const char *mapping;
5760
5761        check_indent_newline(ctx->dl);
5762        print_string(PRINT_ANY, "type", "type %s",
5763                     dpipe_match_type_e2s(match->type));
5764        print_string(PRINT_ANY, "header", " header %s",
5765                     dpipe_header_id2s(ctx, op_info->header_id,
5766                                       op_info->header_global));
5767        print_string(PRINT_ANY, "field", " field %s",
5768                     dpipe_field_id2s(ctx, op_info->header_id,
5769                                      op_info->field_id,
5770                                      op_info->header_global));
5771        mapping = dpipe_mapping_get(ctx, op_info->header_id,
5772                                    op_info->field_id,
5773                                    op_info->header_global);
5774        if (mapping)
5775                print_string(PRINT_ANY, "mapping", " mapping %s", mapping);
5776}
5777
5778static int dpipe_match_parse(struct dpipe_match *match,
5779                             struct nlattr *nl)
5780
5781{
5782        struct nlattr *nla_match[DEVLINK_ATTR_MAX + 1] = {};
5783        int err;
5784
5785        err = mnl_attr_parse_nested(nl, attr_cb, nla_match);
5786        if (err != MNL_CB_OK)
5787                return -EINVAL;
5788
5789        if (!nla_match[DEVLINK_ATTR_DPIPE_MATCH_TYPE] ||
5790            !nla_match[DEVLINK_ATTR_DPIPE_HEADER_INDEX] ||
5791            !nla_match[DEVLINK_ATTR_DPIPE_HEADER_ID] ||
5792            !nla_match[DEVLINK_ATTR_DPIPE_FIELD_ID]) {
5793                return -EINVAL;
5794        }
5795
5796        match->type = mnl_attr_get_u32(nla_match[DEVLINK_ATTR_DPIPE_MATCH_TYPE]);
5797        match->info.header_id = mnl_attr_get_u32(nla_match[DEVLINK_ATTR_DPIPE_HEADER_ID]);
5798        match->info.field_id = mnl_attr_get_u32(nla_match[DEVLINK_ATTR_DPIPE_FIELD_ID]);
5799        match->info.header_global = !!mnl_attr_get_u8(nla_match[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL]);
5800
5801        return 0;
5802}
5803
5804static int dpipe_table_matches_show(struct dpipe_ctx *ctx,
5805                                    struct nlattr *nla_matches)
5806{
5807        struct nlattr *nla_match;
5808        struct dpipe_match match;
5809
5810        mnl_attr_for_each_nested(nla_match, nla_matches) {
5811                pr_out_entry_start(ctx->dl);
5812                if (dpipe_match_parse(&match, nla_match))
5813                        goto err_match_parse;
5814                pr_out_dpipe_match(&match, ctx);
5815                pr_out_entry_end(ctx->dl);
5816        }
5817        return 0;
5818
5819err_match_parse:
5820        pr_out_entry_end(ctx->dl);
5821        return -EINVAL;
5822}
5823
5824static struct resource *
5825resource_find(struct resources *resources, struct resource *resource,
5826              uint64_t resource_id)
5827{
5828        struct list_head *list_head;
5829
5830        if (!resource)
5831                list_head = &resources->resource_list;
5832        else
5833                list_head = &resource->resource_list;
5834
5835        list_for_each_entry(resource, list_head, list) {
5836                struct resource *child_resource;
5837
5838                if (resource->id == resource_id)
5839                        return resource;
5840
5841                child_resource = resource_find(resources, resource,
5842                                               resource_id);
5843                if (child_resource)
5844                        return child_resource;
5845        }
5846        return NULL;
5847}
5848
5849static void
5850resource_path_print(struct dl *dl, struct resources *resources,
5851                    uint64_t resource_id)
5852{
5853        struct resource *resource, *parent_resource;
5854        const char del[] = "/";
5855        int path_len = 0;
5856        char *path;
5857
5858        resource = resource_find(resources, NULL, resource_id);
5859        if (!resource)
5860                return;
5861
5862        for (parent_resource = resource; parent_resource;
5863             parent_resource = parent_resource->parent)
5864                path_len += strlen(parent_resource->name) + 1;
5865
5866        path_len++;
5867        path = calloc(1, path_len);
5868        if (!path)
5869                return;
5870
5871        path += path_len - 1;
5872        for (parent_resource = resource; parent_resource;
5873                parent_resource = parent_resource->parent) {
5874                path -= strlen(parent_resource->name);
5875                memcpy(path, parent_resource->name,
5876                       strlen(parent_resource->name));
5877                path -= strlen(del);
5878                memcpy(path, del, strlen(del));
5879        }
5880        check_indent_newline(dl);
5881        print_string(PRINT_ANY, "resource_path", "resource_path %s", path);
5882        free(path);
5883}
5884
5885static int dpipe_table_show(struct dpipe_ctx *ctx, struct nlattr *nl)
5886{
5887        struct nlattr *nla_table[DEVLINK_ATTR_MAX + 1] = {};
5888        struct dpipe_table *table;
5889        uint32_t resource_units;
5890        bool counters_enabled;
5891        bool resource_valid;
5892        uint32_t size;
5893        int err;
5894
5895        err = mnl_attr_parse_nested(nl, attr_cb, nla_table);
5896        if (err != MNL_CB_OK)
5897                return -EINVAL;
5898
5899        if (!nla_table[DEVLINK_ATTR_DPIPE_TABLE_NAME] ||
5900            !nla_table[DEVLINK_ATTR_DPIPE_TABLE_SIZE] ||
5901            !nla_table[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS] ||
5902            !nla_table[DEVLINK_ATTR_DPIPE_TABLE_MATCHES] ||
5903            !nla_table[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]) {
5904                return -EINVAL;
5905        }
5906
5907        table = dpipe_table_alloc();
5908        if (!table)
5909                return -ENOMEM;
5910
5911        table->name = strdup(mnl_attr_get_str(nla_table[DEVLINK_ATTR_DPIPE_TABLE_NAME]));
5912        size = mnl_attr_get_u32(nla_table[DEVLINK_ATTR_DPIPE_TABLE_SIZE]);
5913        counters_enabled = !!mnl_attr_get_u8(nla_table[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]);
5914
5915        resource_valid = nla_table[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID] &&
5916                         ctx->resources;
5917        if (resource_valid) {
5918                table->resource_id = mnl_attr_get_u64(nla_table[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID]);
5919                table->resource_valid = true;
5920        }
5921
5922        list_add_tail(&table->list, &ctx->tables->table_list);
5923        if (!ctx->print_tables)
5924                return 0;
5925
5926        check_indent_newline(ctx->dl);
5927        print_string(PRINT_ANY, "name", "name %s", table->name);
5928        print_uint(PRINT_ANY, "size", " size %u", size);
5929        print_bool(PRINT_ANY, "counters_enabled", " counters_enabled %s", counters_enabled);
5930
5931        if (resource_valid) {
5932                resource_units = mnl_attr_get_u32(nla_table[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS]);
5933                resource_path_print(ctx->dl, ctx->resources,
5934                                    table->resource_id);
5935                print_uint(PRINT_ANY, "resource_units", " resource_units %u",
5936                           resource_units);
5937        }
5938
5939        pr_out_array_start(ctx->dl, "match");
5940        if (dpipe_table_matches_show(ctx, nla_table[DEVLINK_ATTR_DPIPE_TABLE_MATCHES]))
5941                goto err_matches_show;
5942        pr_out_array_end(ctx->dl);
5943
5944        pr_out_array_start(ctx->dl, "action");
5945        if (dpipe_table_actions_show(ctx, nla_table[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS]))
5946                goto err_actions_show;
5947        pr_out_array_end(ctx->dl);
5948
5949        return 0;
5950
5951err_actions_show:
5952err_matches_show:
5953        pr_out_array_end(ctx->dl);
5954        return -EINVAL;
5955}
5956
5957static int dpipe_tables_show(struct dpipe_ctx *ctx, struct nlattr **tb)
5958{
5959        struct nlattr *nla_tables = tb[DEVLINK_ATTR_DPIPE_TABLES];
5960        struct nlattr *nla_table;
5961
5962        mnl_attr_for_each_nested(nla_table, nla_tables) {
5963                if (ctx->print_tables)
5964                        pr_out_handle_start_arr(ctx->dl, tb);
5965                if (dpipe_table_show(ctx, nla_table))
5966                        goto err_table_show;
5967                if (ctx->print_tables)
5968                        pr_out_handle_end(ctx->dl);
5969        }
5970        return 0;
5971
5972err_table_show:
5973        if (ctx->print_tables)
5974                pr_out_handle_end(ctx->dl);
5975        return -EINVAL;
5976}
5977
5978static int cmd_dpipe_table_show_cb(const struct nlmsghdr *nlh, void *data)
5979{
5980        struct dpipe_ctx *ctx = data;
5981        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
5982        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
5983
5984        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5985        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5986            !tb[DEVLINK_ATTR_DPIPE_TABLES])
5987                return MNL_CB_ERROR;
5988
5989        if (dpipe_tables_show(ctx, tb))
5990                return MNL_CB_ERROR;
5991        return MNL_CB_OK;
5992}
5993
5994static int cmd_resource_dump_cb(const struct nlmsghdr *nlh, void *data);
5995
5996static int cmd_dpipe_table_show(struct dl *dl)
5997{
5998        struct nlmsghdr *nlh;
5999        struct dpipe_ctx dpipe_ctx = {};
6000        struct resource_ctx resource_ctx = {};
6001        uint16_t flags = NLM_F_REQUEST;
6002        int err;
6003
6004        err = dl_argv_parse(dl, DL_OPT_HANDLE, DL_OPT_DPIPE_TABLE_NAME);
6005        if (err)
6006                return err;
6007
6008        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags);
6009
6010        err = dpipe_ctx_init(&dpipe_ctx, dl);
6011        if (err)
6012                return err;
6013
6014        dpipe_ctx.print_tables = true;
6015
6016        dl_opts_put(nlh, dl);
6017        err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_header_cb,
6018                                  &dpipe_ctx);
6019        if (err) {
6020                pr_err("error get headers %s\n", strerror(dpipe_ctx.err));
6021                goto err_headers_get;
6022        }
6023
6024        err = resource_ctx_init(&resource_ctx, dl);
6025        if (err)
6026                goto err_resource_ctx_init;
6027
6028        resource_ctx.print_resources = false;
6029        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RESOURCE_DUMP, flags);
6030        dl_opts_put(nlh, dl);
6031        err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_resource_dump_cb,
6032                                  &resource_ctx);
6033        if (!err)
6034                dpipe_ctx.resources = resource_ctx.resources;
6035
6036        flags = NLM_F_REQUEST | NLM_F_ACK;
6037        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_TABLE_GET, flags);
6038        dl_opts_put(nlh, dl);
6039
6040        pr_out_section_start(dl, "table");
6041        _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_table_show_cb, &dpipe_ctx);
6042        pr_out_section_end(dl);
6043
6044        resource_ctx_fini(&resource_ctx);
6045        dpipe_ctx_fini(&dpipe_ctx);
6046        return 0;
6047
6048err_resource_ctx_init:
6049err_headers_get:
6050        dpipe_ctx_fini(&dpipe_ctx);
6051        return err;
6052}
6053
6054static int cmd_dpipe_table_set(struct dl *dl)
6055{
6056        struct nlmsghdr *nlh;
6057        int err;
6058
6059        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
6060                               NLM_F_REQUEST | NLM_F_ACK);
6061
6062        err = dl_argv_parse_put(nlh, dl,
6063                                DL_OPT_HANDLE | DL_OPT_DPIPE_TABLE_NAME |
6064                                DL_OPT_DPIPE_TABLE_COUNTERS, 0);
6065        if (err)
6066                return err;
6067
6068        return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
6069}
6070
6071enum dpipe_value_type {
6072        DPIPE_VALUE_TYPE_VALUE,
6073        DPIPE_VALUE_TYPE_MASK,
6074};
6075
6076static const char *
6077dpipe_value_type_e2s(enum dpipe_value_type type)
6078{
6079        switch (type) {
6080        case DPIPE_VALUE_TYPE_VALUE:
6081                return "value";
6082        case DPIPE_VALUE_TYPE_MASK:
6083                return "value_mask";
6084        default:
6085                return "<unknown>";
6086        }
6087}
6088
6089struct dpipe_field_printer {
6090        unsigned int field_id;
6091        void (*printer)(struct dpipe_ctx *, enum dpipe_value_type, void *);
6092};
6093
6094struct dpipe_header_printer {
6095        struct dpipe_field_printer *printers;
6096        unsigned int printers_count;
6097        unsigned int header_id;
6098};
6099
6100static void dpipe_field_printer_ipv4_addr(struct dpipe_ctx *ctx,
6101                                          enum dpipe_value_type type,
6102                                          void *value)
6103{
6104        struct in_addr ip_addr;
6105
6106        ip_addr.s_addr = htonl(*(uint32_t *)value);
6107        check_indent_newline(ctx->dl);
6108        print_string_name_value(dpipe_value_type_e2s(type), inet_ntoa(ip_addr));
6109}
6110
6111static void
6112dpipe_field_printer_ethernet_addr(struct dpipe_ctx *ctx,
6113                                  enum dpipe_value_type type,
6114                                  void *value)
6115{
6116        check_indent_newline(ctx->dl);
6117        print_string_name_value(dpipe_value_type_e2s(type),
6118                                ether_ntoa((struct ether_addr *)value));
6119}
6120
6121static void dpipe_field_printer_ipv6_addr(struct dpipe_ctx *ctx,
6122                                          enum dpipe_value_type type,
6123                                          void *value)
6124{
6125        char str[INET6_ADDRSTRLEN];
6126
6127        inet_ntop(AF_INET6, value, str, INET6_ADDRSTRLEN);
6128        check_indent_newline(ctx->dl);
6129        print_string_name_value(dpipe_value_type_e2s(type), str);
6130}
6131
6132static struct dpipe_field_printer dpipe_field_printers_ipv4[] = {
6133        {
6134                .printer = dpipe_field_printer_ipv4_addr,
6135                .field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP,
6136        }
6137};
6138
6139static struct dpipe_header_printer dpipe_header_printer_ipv4  = {
6140        .printers = dpipe_field_printers_ipv4,
6141        .printers_count = ARRAY_SIZE(dpipe_field_printers_ipv4),
6142        .header_id = DEVLINK_DPIPE_HEADER_IPV4,
6143};
6144
6145static struct dpipe_field_printer dpipe_field_printers_ethernet[] = {
6146        {
6147                .printer = dpipe_field_printer_ethernet_addr,
6148                .field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC,
6149        },
6150};
6151
6152static struct dpipe_header_printer dpipe_header_printer_ethernet = {
6153        .printers = dpipe_field_printers_ethernet,
6154        .printers_count = ARRAY_SIZE(dpipe_field_printers_ethernet),
6155        .header_id = DEVLINK_DPIPE_HEADER_ETHERNET,
6156};
6157
6158static struct dpipe_field_printer dpipe_field_printers_ipv6[] = {
6159        {
6160                .printer = dpipe_field_printer_ipv6_addr,
6161                .field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP,
6162        }
6163};
6164
6165static struct dpipe_header_printer dpipe_header_printer_ipv6 = {
6166        .printers = dpipe_field_printers_ipv6,
6167        .printers_count = ARRAY_SIZE(dpipe_field_printers_ipv6),
6168        .header_id = DEVLINK_DPIPE_HEADER_IPV6,
6169};
6170
6171static struct dpipe_header_printer *dpipe_header_printers[] = {
6172        &dpipe_header_printer_ipv4,
6173        &dpipe_header_printer_ethernet,
6174        &dpipe_header_printer_ipv6,
6175};
6176
6177static int dpipe_print_prot_header(struct dpipe_ctx *ctx,
6178                                   struct dpipe_op_info *info,
6179                                   enum dpipe_value_type type,
6180                                   void *value)
6181{
6182        unsigned int header_printers_count = ARRAY_SIZE(dpipe_header_printers);
6183        struct dpipe_header_printer *header_printer;
6184        struct dpipe_field_printer *field_printer;
6185        unsigned int field_printers_count;
6186        int j;
6187        int i;
6188
6189        for (i = 0; i < header_printers_count; i++) {
6190                header_printer = dpipe_header_printers[i];
6191                if (header_printer->header_id != info->header_id)
6192                        continue;
6193                field_printers_count = header_printer->printers_count;
6194                for (j = 0; j < field_printers_count; j++) {
6195                        field_printer = &header_printer->printers[j];
6196                        if (field_printer->field_id != info->field_id)
6197                                continue;
6198                        field_printer->printer(ctx, type, value);
6199                        return 0;
6200                }
6201        }
6202
6203        return -EINVAL;
6204}
6205
6206static void __pr_out_entry_value(struct dpipe_ctx *ctx,
6207                                 void *value,
6208                                 unsigned int value_len,
6209                                 struct dpipe_op_info *info,
6210                                 enum dpipe_value_type type)
6211{
6212        if (info->header_global &&
6213            !dpipe_print_prot_header(ctx, info, type, value))
6214                return;
6215
6216        if (value_len == sizeof(uint32_t)) {
6217                uint32_t *value_32 = value;
6218
6219                check_indent_newline(ctx->dl);
6220                print_uint_name_value(dpipe_value_type_e2s(type), *value_32);
6221        }
6222}
6223
6224static void pr_out_dpipe_entry_value(struct dpipe_ctx *ctx,
6225                                     struct nlattr **nla_match_value,
6226                                     struct dpipe_op_info *info)
6227{
6228        void *value, *value_mask;
6229        uint32_t value_mapping;
6230        uint16_t value_len;
6231        bool mask, mapping;
6232
6233        mask = !!nla_match_value[DEVLINK_ATTR_DPIPE_VALUE_MASK];
6234        mapping = !!nla_match_value[DEVLINK_ATTR_DPIPE_VALUE_MAPPING];
6235
6236        value_len = mnl_attr_get_payload_len(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]);
6237        value = mnl_attr_get_payload(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]);
6238
6239        if (mapping) {
6240                value_mapping = mnl_attr_get_u32(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE_MAPPING]);
6241                check_indent_newline(ctx->dl);
6242                print_uint(PRINT_ANY, "mapping_value", "mapping_value %u", value_mapping);
6243        }
6244
6245        if (mask) {
6246                value_mask = mnl_attr_get_payload(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]);
6247                __pr_out_entry_value(ctx, value_mask, value_len, info,
6248                                     DPIPE_VALUE_TYPE_MASK);
6249        }
6250
6251        __pr_out_entry_value(ctx, value, value_len, info, DPIPE_VALUE_TYPE_VALUE);
6252}
6253
6254static int dpipe_entry_match_value_show(struct dpipe_ctx *ctx,
6255                                        struct nlattr *nl)
6256{
6257        struct nlattr *nla_match_value[DEVLINK_ATTR_MAX + 1] = {};
6258        struct dpipe_match match;
6259        int err;
6260
6261        err = mnl_attr_parse_nested(nl, attr_cb, nla_match_value);
6262        if (err != MNL_CB_OK)
6263                return -EINVAL;
6264
6265        if (!nla_match_value[DEVLINK_ATTR_DPIPE_MATCH] ||
6266            !nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]) {
6267                return -EINVAL;
6268        }
6269
6270        pr_out_entry_start(ctx->dl);
6271        if (dpipe_match_parse(&match,
6272                              nla_match_value[DEVLINK_ATTR_DPIPE_MATCH]))
6273                goto err_match_parse;
6274        pr_out_dpipe_match(&match, ctx);
6275        pr_out_dpipe_entry_value(ctx, nla_match_value, &match.info);
6276        pr_out_entry_end(ctx->dl);
6277
6278        return 0;
6279
6280err_match_parse:
6281        pr_out_entry_end(ctx->dl);
6282        return -EINVAL;
6283}
6284
6285static int dpipe_entry_action_value_show(struct dpipe_ctx *ctx,
6286                                         struct nlattr *nl)
6287{
6288        struct nlattr *nla_action_value[DEVLINK_ATTR_MAX + 1] = {};
6289        struct dpipe_action action;
6290        int err;
6291
6292        err = mnl_attr_parse_nested(nl, attr_cb, nla_action_value);
6293        if (err != MNL_CB_OK)
6294                return -EINVAL;
6295
6296        if (!nla_action_value[DEVLINK_ATTR_DPIPE_ACTION] ||
6297            !nla_action_value[DEVLINK_ATTR_DPIPE_VALUE]) {
6298                return -EINVAL;
6299        }
6300
6301        pr_out_entry_start(ctx->dl);
6302        if (dpipe_action_parse(&action,
6303                               nla_action_value[DEVLINK_ATTR_DPIPE_ACTION]))
6304                goto err_action_parse;
6305        pr_out_dpipe_action(&action, ctx);
6306        pr_out_dpipe_entry_value(ctx, nla_action_value, &action.info);
6307        pr_out_entry_end(ctx->dl);
6308
6309        return 0;
6310
6311err_action_parse:
6312        pr_out_entry_end(ctx->dl);
6313        return -EINVAL;
6314}
6315
6316static int
6317dpipe_tables_action_values_show(struct dpipe_ctx *ctx,
6318                                struct nlattr *nla_action_values)
6319{
6320        struct nlattr *nla_action_value;
6321
6322        mnl_attr_for_each_nested(nla_action_value, nla_action_values) {
6323                if (dpipe_entry_action_value_show(ctx, nla_action_value))
6324                        return -EINVAL;
6325        }
6326        return 0;
6327}
6328
6329static int
6330dpipe_tables_match_values_show(struct dpipe_ctx *ctx,
6331                               struct nlattr *nla_match_values)
6332{
6333        struct nlattr *nla_match_value;
6334
6335        mnl_attr_for_each_nested(nla_match_value, nla_match_values) {
6336                if (dpipe_entry_match_value_show(ctx, nla_match_value))
6337                        return -EINVAL;
6338        }
6339        return 0;
6340}
6341
6342static int dpipe_entry_show(struct dpipe_ctx *ctx, struct nlattr *nl)
6343{
6344        struct nlattr *nla_entry[DEVLINK_ATTR_MAX + 1] = {};
6345        uint32_t entry_index;
6346        uint64_t counter;
6347        int err;
6348
6349        err = mnl_attr_parse_nested(nl, attr_cb, nla_entry);
6350        if (err != MNL_CB_OK)
6351                return -EINVAL;
6352
6353        if (!nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_INDEX] ||
6354            !nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES] ||
6355            !nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES]) {
6356                return -EINVAL;
6357        }
6358
6359        check_indent_newline(ctx->dl);
6360        entry_index = mnl_attr_get_u32(nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_INDEX]);
6361        print_uint(PRINT_ANY, "index", "index %u", entry_index);
6362
6363        if (nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER]) {
6364                counter = mnl_attr_get_u64(nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER]);
6365                print_uint(PRINT_ANY, "counter", " counter %u", counter);
6366        }
6367
6368        pr_out_array_start(ctx->dl, "match_value");
6369        if (dpipe_tables_match_values_show(ctx,
6370                                           nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES]))
6371                goto err_match_values_show;
6372        pr_out_array_end(ctx->dl);
6373
6374        pr_out_array_start(ctx->dl, "action_value");
6375        if (dpipe_tables_action_values_show(ctx,
6376                                            nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES]))
6377                goto err_action_values_show;
6378        pr_out_array_end(ctx->dl);
6379        return 0;
6380
6381err_action_values_show:
6382err_match_values_show:
6383        pr_out_array_end(ctx->dl);
6384        return -EINVAL;
6385}
6386
6387static int dpipe_table_entries_show(struct dpipe_ctx *ctx, struct nlattr **tb)
6388{
6389        struct nlattr *nla_entries = tb[DEVLINK_ATTR_DPIPE_ENTRIES];
6390        struct nlattr *nla_entry;
6391
6392        mnl_attr_for_each_nested(nla_entry, nla_entries) {
6393                pr_out_handle_start_arr(ctx->dl, tb);
6394                if (dpipe_entry_show(ctx, nla_entry))
6395                        goto err_entry_show;
6396                pr_out_handle_end(ctx->dl);
6397        }
6398        return 0;
6399
6400err_entry_show:
6401        pr_out_handle_end(ctx->dl);
6402        return -EINVAL;
6403}
6404
6405static int cmd_dpipe_table_entry_dump_cb(const struct nlmsghdr *nlh, void *data)
6406{
6407        struct dpipe_ctx *ctx = data;
6408        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
6409        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
6410
6411        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
6412        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
6413            !tb[DEVLINK_ATTR_DPIPE_ENTRIES])
6414                return MNL_CB_ERROR;
6415
6416        if (dpipe_table_entries_show(ctx, tb))
6417                return MNL_CB_ERROR;
6418        return MNL_CB_OK;
6419}
6420
6421static int cmd_dpipe_table_dump(struct dl *dl)
6422{
6423        struct nlmsghdr *nlh;
6424        struct dpipe_ctx ctx = {};
6425        uint16_t flags = NLM_F_REQUEST;
6426        int err;
6427
6428        err = dpipe_ctx_init(&ctx, dl);
6429        if (err)
6430                return err;
6431
6432        err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_DPIPE_TABLE_NAME, 0);
6433        if (err)
6434                goto out;
6435
6436        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags);
6437        dl_opts_put(nlh, dl);
6438        err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_header_cb, &ctx);
6439        if (err) {
6440                pr_err("error get headers %s\n", strerror(ctx.err));
6441                goto out;
6442        }
6443
6444        flags = NLM_F_REQUEST | NLM_F_ACK;
6445        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_ENTRIES_GET, flags);
6446        dl_opts_put(nlh, dl);
6447
6448        pr_out_section_start(dl, "table_entry");
6449        _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_table_entry_dump_cb, &ctx);
6450        pr_out_section_end(dl);
6451out:
6452        dpipe_ctx_fini(&ctx);
6453        return err;
6454}
6455
6456static int cmd_dpipe_table(struct dl *dl)
6457{
6458        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
6459                cmd_dpipe_help();
6460                return 0;
6461        } else if (dl_argv_match(dl, "show")) {
6462                dl_arg_inc(dl);
6463                return cmd_dpipe_table_show(dl);
6464        } else if (dl_argv_match(dl, "set")) {
6465                dl_arg_inc(dl);
6466                return cmd_dpipe_table_set(dl);
6467        }  else if (dl_argv_match(dl, "dump")) {
6468                dl_arg_inc(dl);
6469                return cmd_dpipe_table_dump(dl);
6470        }
6471        pr_err("Command \"%s\" not found\n", dl_argv(dl));
6472        return -ENOENT;
6473}
6474
6475static int cmd_dpipe(struct dl *dl)
6476{
6477        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
6478                cmd_dpipe_help();
6479                return 0;
6480        } else if (dl_argv_match(dl, "header")) {
6481                dl_arg_inc(dl);
6482                return cmd_dpipe_header(dl);
6483        } else if (dl_argv_match(dl, "table")) {
6484                dl_arg_inc(dl);
6485                return cmd_dpipe_table(dl);
6486        }
6487        pr_err("Command \"%s\" not found\n", dl_argv(dl));
6488        return -ENOENT;
6489}
6490
6491static int
6492resource_parse(struct resource_ctx *ctx, struct resource *resource,
6493               struct nlattr **nla_resource)
6494{
6495        if (!nla_resource[DEVLINK_ATTR_RESOURCE_NAME] ||
6496            !nla_resource[DEVLINK_ATTR_RESOURCE_SIZE] ||
6497            !nla_resource[DEVLINK_ATTR_RESOURCE_ID] ||
6498            !nla_resource[DEVLINK_ATTR_RESOURCE_UNIT] ||
6499            !nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_MIN] ||
6500            !nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_MAX] ||
6501            !nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_GRAN]) {
6502                return -EINVAL;
6503        }
6504
6505        resource->name = strdup(mnl_attr_get_str(nla_resource[DEVLINK_ATTR_RESOURCE_NAME]));
6506        resource->size = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE]);
6507        resource->id = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_ID]);
6508        resource->unit = mnl_attr_get_u8(nla_resource[DEVLINK_ATTR_RESOURCE_UNIT]);
6509        resource->size_min = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_MIN]);
6510        resource->size_max = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_MAX]);
6511        resource->size_gran = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_GRAN]);
6512
6513        if (nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_NEW])
6514                resource->size_new = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_NEW]);
6515        else
6516                resource->size_new = resource->size;
6517
6518        if (nla_resource[DEVLINK_ATTR_RESOURCE_OCC]) {
6519                resource->size_occ = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_OCC]);
6520                resource->occ_valid = true;
6521        }
6522
6523        if (resource->size_new != resource->size)
6524                ctx->pending_change = true;
6525
6526        return 0;
6527}
6528
6529static int
6530resource_get(struct resource_ctx *ctx, struct resource *resource,
6531             struct resource *parent_resource, struct nlattr *nl)
6532{
6533        struct nlattr *nla_resource[DEVLINK_ATTR_MAX + 1] = {};
6534        struct nlattr *nla_child_resource;
6535        struct nlattr *nla_resources;
6536        bool top = false;
6537        int err;
6538
6539        if (!resource) {
6540                nla_resources = nl;
6541                top = true;
6542                goto out;
6543        }
6544
6545        err = mnl_attr_parse_nested(nl, attr_cb, nla_resource);
6546        if (err != MNL_CB_OK)
6547                return -EINVAL;
6548
6549        err = resource_parse(ctx, resource, nla_resource);
6550        if (err)
6551                return err;
6552
6553        resource->parent = parent_resource;
6554        if (!nla_resource[DEVLINK_ATTR_RESOURCE_LIST])
6555                return 0;
6556
6557        resource->size_valid = !!mnl_attr_get_u8(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_VALID]);
6558        nla_resources = nla_resource[DEVLINK_ATTR_RESOURCE_LIST];
6559out:
6560        mnl_attr_for_each_nested(nla_child_resource, nla_resources) {
6561                struct resource *child_resource;
6562                struct list_head *list;
6563
6564                child_resource = resource_alloc();
6565                if (!child_resource)
6566                        return -ENOMEM;
6567
6568                if (top)
6569                        list = &ctx->resources->resource_list;
6570                else
6571                        list = &resource->resource_list;
6572
6573                list_add_tail(&child_resource->list, list);
6574                err = resource_get(ctx, child_resource, resource,
6575                                   nla_child_resource);
6576                if (err)
6577                        return err;
6578        }
6579
6580        return 0;
6581}
6582
6583static const char *resource_unit_str_get(enum devlink_resource_unit unit)
6584{
6585        switch (unit) {
6586        case DEVLINK_RESOURCE_UNIT_ENTRY: return "entry";
6587        default: return "<unknown unit>";
6588        }
6589}
6590
6591static void resource_show(struct resource *resource,
6592                          struct resource_ctx *ctx)
6593{
6594        struct resource *child_resource;
6595        struct dpipe_table *table;
6596        struct dl *dl = ctx->dl;
6597        bool array = false;
6598
6599        check_indent_newline(dl);
6600        print_string(PRINT_ANY, "name", "name %s", resource->name);
6601        if (dl->verbose)
6602                resource_path_print(dl, ctx->resources, resource->id);
6603        pr_out_u64(dl, "size", resource->size);
6604        if (resource->size != resource->size_new)
6605                pr_out_u64(dl, "size_new", resource->size_new);
6606        if (resource->occ_valid)
6607                print_uint(PRINT_ANY, "occ", " occ %u",  resource->size_occ);
6608        print_string(PRINT_ANY, "unit", " unit %s",
6609                     resource_unit_str_get(resource->unit));
6610
6611        if (resource->size_min != resource->size_max) {
6612                print_uint(PRINT_ANY, "size_min", " size_min %u",
6613                           resource->size_min);
6614                pr_out_u64(dl, "size_max", resource->size_max);
6615                print_uint(PRINT_ANY, "size_gran", " size_gran %u",
6616                           resource->size_gran);
6617        }
6618
6619        list_for_each_entry(table, &ctx->tables->table_list, list)
6620                if (table->resource_id == resource->id &&
6621                    table->resource_valid)
6622                        array = true;
6623
6624        if (array)
6625                pr_out_array_start(dl, "dpipe_tables");
6626        else
6627                print_string(PRINT_ANY, "dpipe_tables", " dpipe_tables none",
6628                             "none");
6629
6630        list_for_each_entry(table, &ctx->tables->table_list, list) {
6631                if (table->resource_id != resource->id ||
6632                    !table->resource_valid)
6633                        continue;
6634                pr_out_entry_start(dl);
6635                check_indent_newline(dl);
6636                print_string(PRINT_ANY, "table_name", "table_name %s",
6637                             table->name);
6638                pr_out_entry_end(dl);
6639        }
6640        if (array)
6641                pr_out_array_end(dl);
6642
6643        if (list_empty(&resource->resource_list))
6644                return;
6645
6646        if (ctx->pending_change) {
6647                check_indent_newline(dl);
6648                print_string(PRINT_ANY, "size_valid", "size_valid %s",
6649                             resource->size_valid ? "true" : "false");
6650        }
6651        pr_out_array_start(dl, "resources");
6652        list_for_each_entry(child_resource, &resource->resource_list, list) {
6653                pr_out_entry_start(dl);
6654                resource_show(child_resource, ctx);
6655                pr_out_entry_end(dl);
6656        }
6657        pr_out_array_end(dl);
6658}
6659
6660static void
6661resources_show(struct resource_ctx *ctx, struct nlattr **tb)
6662{
6663        struct resources *resources = ctx->resources;
6664        struct resource *resource;
6665
6666        list_for_each_entry(resource, &resources->resource_list, list) {
6667                pr_out_handle_start_arr(ctx->dl, tb);
6668                resource_show(resource, ctx);
6669                pr_out_handle_end(ctx->dl);
6670        }
6671}
6672
6673static int resources_get(struct resource_ctx *ctx, struct nlattr **tb)
6674{
6675        return resource_get(ctx, NULL, NULL, tb[DEVLINK_ATTR_RESOURCE_LIST]);
6676}
6677
6678static int cmd_resource_dump_cb(const struct nlmsghdr *nlh, void *data)
6679{
6680        struct resource_ctx *ctx = data;
6681        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
6682        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
6683        int err;
6684
6685        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
6686        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
6687            !tb[DEVLINK_ATTR_RESOURCE_LIST])
6688                return MNL_CB_ERROR;
6689
6690        err = resources_get(ctx, tb);
6691        if (err) {
6692                ctx->err = err;
6693                return MNL_CB_ERROR;
6694        }
6695
6696        if (ctx->print_resources)
6697                resources_show(ctx, tb);
6698
6699        return MNL_CB_OK;
6700}
6701
6702static int cmd_resource_show(struct dl *dl)
6703{
6704        struct nlmsghdr *nlh;
6705        struct dpipe_ctx dpipe_ctx = {};
6706        struct resource_ctx resource_ctx = {};
6707        int err;
6708
6709        err = dl_argv_parse(dl, DL_OPT_HANDLE, 0);
6710        if (err)
6711                return err;
6712
6713        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_TABLE_GET,
6714                               NLM_F_REQUEST);
6715        dl_opts_put(nlh, dl);
6716
6717        err = dpipe_ctx_init(&dpipe_ctx, dl);
6718        if (err)
6719                return err;
6720
6721        err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_table_show_cb,
6722                                  &dpipe_ctx);
6723        if (err) {
6724                pr_err("error get tables %s\n", strerror(dpipe_ctx.err));
6725                goto out;
6726        }
6727
6728        err = resource_ctx_init(&resource_ctx, dl);
6729        if (err)
6730                goto out;
6731
6732        resource_ctx.print_resources = true;
6733        resource_ctx.tables = dpipe_ctx.tables;
6734        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RESOURCE_DUMP,
6735                               NLM_F_REQUEST | NLM_F_ACK);
6736        dl_opts_put(nlh, dl);
6737        pr_out_section_start(dl, "resources");
6738        err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_resource_dump_cb,
6739                                  &resource_ctx);
6740        pr_out_section_end(dl);
6741        resource_ctx_fini(&resource_ctx);
6742out:
6743        dpipe_ctx_fini(&dpipe_ctx);
6744        return err;
6745}
6746
6747static void cmd_resource_help(void)
6748{
6749        pr_err("Usage: devlink resource show DEV\n"
6750               "       devlink resource set DEV path PATH size SIZE\n");
6751}
6752
6753static struct resource *
6754resource_find_by_name(struct list_head *list, char *name)
6755{
6756        struct resource *resource;
6757
6758        list_for_each_entry(resource, list, list) {
6759                if (!strcmp(resource->name, name))
6760                        return resource;
6761        }
6762        return NULL;
6763}
6764
6765static int
6766resource_path_parse(struct resource_ctx *ctx, const char *resource_path,
6767                    uint32_t *p_resource_id, bool *p_resource_valid)
6768{
6769        struct resource *resource;
6770        uint32_t resource_id = 0;
6771        char *resource_path_dup;
6772        struct list_head *list;
6773        const char del[] = "/";
6774        char *resource_name;
6775
6776        resource_path_dup = strdup(resource_path);
6777        list = &ctx->resources->resource_list;
6778        resource_name = strtok(resource_path_dup, del);
6779        while (resource_name != NULL) {
6780                resource = resource_find_by_name(list, resource_name);
6781                if (!resource)
6782                        goto err_resource_lookup;
6783
6784                list = &resource->resource_list;
6785                resource_name = strtok(NULL, del);
6786                resource_id = resource->id;
6787        }
6788        free(resource_path_dup);
6789        *p_resource_valid = true;
6790        *p_resource_id = resource_id;
6791        return 0;
6792
6793err_resource_lookup:
6794        free(resource_path_dup);
6795        return -EINVAL;
6796}
6797
6798static int cmd_resource_set(struct dl *dl)
6799{
6800        struct nlmsghdr *nlh;
6801        struct resource_ctx ctx = {};
6802        int err;
6803
6804        err = resource_ctx_init(&ctx, dl);
6805        if (err)
6806                return err;
6807
6808        ctx.print_resources = false;
6809        err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_RESOURCE_PATH |
6810                            DL_OPT_RESOURCE_SIZE, 0);
6811        if (err)
6812                goto out;
6813
6814        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RESOURCE_DUMP,
6815                               NLM_F_REQUEST);
6816        dl_opts_put(nlh, dl);
6817        err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_resource_dump_cb, &ctx);
6818        if (err) {
6819                pr_err("error getting resources %s\n", strerror(ctx.err));
6820                goto out;
6821        }
6822
6823        err = resource_path_parse(&ctx, dl->opts.resource_path,
6824                                  &dl->opts.resource_id,
6825                                  &dl->opts.resource_id_valid);
6826        if (err) {
6827                pr_err("error parsing resource path %s\n", strerror(-err));
6828                goto out;
6829        }
6830
6831        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RESOURCE_SET,
6832                               NLM_F_REQUEST | NLM_F_ACK);
6833
6834        dl_opts_put(nlh, dl);
6835        err = _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
6836out:
6837        resource_ctx_fini(&ctx);
6838        return err;
6839}
6840
6841static int cmd_resource(struct dl *dl)
6842{
6843        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
6844                cmd_resource_help();
6845                return 0;
6846        } else if (dl_argv_match(dl, "show")) {
6847                dl_arg_inc(dl);
6848                return cmd_resource_show(dl);
6849        } else if (dl_argv_match(dl, "set")) {
6850                dl_arg_inc(dl);
6851                return cmd_resource_set(dl);
6852        }
6853        pr_err("Command \"%s\" not found\n", dl_argv(dl));
6854        return -ENOENT;
6855}
6856
6857static void pr_out_region_handle_start(struct dl *dl, struct nlattr **tb)
6858{
6859        const char *bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
6860        const char *dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
6861        const char *region_name = mnl_attr_get_str(tb[DEVLINK_ATTR_REGION_NAME]);
6862        char buf[256];
6863
6864        sprintf(buf, "%s/%s/%s", bus_name, dev_name, region_name);
6865        if (dl->json_output)
6866                open_json_object(buf);
6867        else
6868                pr_out("%s:", buf);
6869}
6870
6871static void pr_out_region_handle_end(struct dl *dl)
6872{
6873        if (dl->json_output)
6874                close_json_object();
6875        else
6876                pr_out("\n");
6877}
6878
6879static void pr_out_region_snapshots_start(struct dl *dl, bool array)
6880{
6881        __pr_out_indent_newline(dl);
6882        if (dl->json_output)
6883                open_json_array(PRINT_JSON, "snapshot");
6884        else
6885                pr_out("snapshot %s", array ? "[" : "");
6886}
6887
6888static void pr_out_region_snapshots_end(struct dl *dl, bool array)
6889{
6890        if (dl->json_output)
6891                close_json_array(PRINT_JSON, NULL);
6892        else if (array)
6893                pr_out("]");
6894}
6895
6896static void pr_out_region_snapshots_id(struct dl *dl, struct nlattr **tb, int index)
6897{
6898        uint32_t snapshot_id;
6899
6900        if (!tb[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
6901                return;
6902
6903        snapshot_id = mnl_attr_get_u32(tb[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
6904
6905        if (dl->json_output)
6906                print_uint(PRINT_JSON, NULL, NULL, snapshot_id);
6907        else
6908                pr_out("%s%u", index ? " " : "", snapshot_id);
6909}
6910
6911static void pr_out_snapshots(struct dl *dl, struct nlattr **tb)
6912{
6913        struct nlattr *tb_snapshot[DEVLINK_ATTR_MAX + 1] = {};
6914        struct nlattr *nla_sanpshot;
6915        int err, index = 0;
6916
6917        pr_out_region_snapshots_start(dl, true);
6918        mnl_attr_for_each_nested(nla_sanpshot, tb[DEVLINK_ATTR_REGION_SNAPSHOTS]) {
6919                err = mnl_attr_parse_nested(nla_sanpshot, attr_cb, tb_snapshot);
6920                if (err != MNL_CB_OK)
6921                        return;
6922                pr_out_region_snapshots_id(dl, tb_snapshot, index++);
6923        }
6924        pr_out_region_snapshots_end(dl, true);
6925}
6926
6927static void pr_out_snapshot(struct dl *dl, struct nlattr **tb)
6928{
6929        pr_out_region_snapshots_start(dl, false);
6930        pr_out_region_snapshots_id(dl, tb, 0);
6931        pr_out_region_snapshots_end(dl, false);
6932}
6933
6934static void pr_out_region(struct dl *dl, struct nlattr **tb)
6935{
6936        pr_out_region_handle_start(dl, tb);
6937
6938        if (tb[DEVLINK_ATTR_REGION_SIZE])
6939                pr_out_u64(dl, "size",
6940                           mnl_attr_get_u64(tb[DEVLINK_ATTR_REGION_SIZE]));
6941
6942        if (tb[DEVLINK_ATTR_REGION_SNAPSHOTS])
6943                pr_out_snapshots(dl, tb);
6944
6945        if (tb[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
6946                pr_out_snapshot(dl, tb);
6947
6948        pr_out_region_handle_end(dl);
6949}
6950
6951static int cmd_region_show_cb(const struct nlmsghdr *nlh, void *data)
6952{
6953        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
6954        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
6955        struct dl *dl = data;
6956
6957        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
6958        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
6959            !tb[DEVLINK_ATTR_REGION_NAME] || !tb[DEVLINK_ATTR_REGION_SIZE])
6960                return MNL_CB_ERROR;
6961
6962        pr_out_region(dl, tb);
6963
6964        return MNL_CB_OK;
6965}
6966
6967static int cmd_region_show(struct dl *dl)
6968{
6969        struct nlmsghdr *nlh;
6970        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
6971        int err;
6972
6973        if (dl_argc(dl) == 0)
6974                flags |= NLM_F_DUMP;
6975
6976        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_GET, flags);
6977
6978        if (dl_argc(dl) > 0) {
6979                err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION, 0);
6980                if (err)
6981                        return err;
6982        }
6983
6984        pr_out_section_start(dl, "regions");
6985        err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_region_show_cb, dl);
6986        pr_out_section_end(dl);
6987        return err;
6988}
6989
6990static int cmd_region_snapshot_del(struct dl *dl)
6991{
6992        struct nlmsghdr *nlh;
6993        int err;
6994
6995        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_DEL,
6996                               NLM_F_REQUEST | NLM_F_ACK);
6997
6998        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION |
6999                                DL_OPT_REGION_SNAPSHOT_ID, 0);
7000        if (err)
7001                return err;
7002
7003        return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
7004}
7005
7006static int cmd_region_read_cb(const struct nlmsghdr *nlh, void *data)
7007{
7008        struct nlattr *nla_entry, *nla_chunk_data, *nla_chunk_addr;
7009        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
7010        struct nlattr *tb_field[DEVLINK_ATTR_MAX + 1] = {};
7011        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
7012        struct dl *dl = data;
7013        int err;
7014
7015        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
7016        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
7017            !tb[DEVLINK_ATTR_REGION_CHUNKS])
7018                return MNL_CB_ERROR;
7019
7020        mnl_attr_for_each_nested(nla_entry, tb[DEVLINK_ATTR_REGION_CHUNKS]) {
7021                err = mnl_attr_parse_nested(nla_entry, attr_cb, tb_field);
7022                if (err != MNL_CB_OK)
7023                        return MNL_CB_ERROR;
7024
7025                nla_chunk_data = tb_field[DEVLINK_ATTR_REGION_CHUNK_DATA];
7026                if (!nla_chunk_data)
7027                        continue;
7028
7029                nla_chunk_addr = tb_field[DEVLINK_ATTR_REGION_CHUNK_ADDR];
7030                if (!nla_chunk_addr)
7031                        continue;
7032
7033                pr_out_region_chunk(dl, mnl_attr_get_payload(nla_chunk_data),
7034                                    mnl_attr_get_payload_len(nla_chunk_data),
7035                                    mnl_attr_get_u64(nla_chunk_addr));
7036        }
7037        return MNL_CB_OK;
7038}
7039
7040static int cmd_region_dump(struct dl *dl)
7041{
7042        struct nlmsghdr *nlh;
7043        int err;
7044
7045        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_READ,
7046                               NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
7047
7048        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION |
7049                                DL_OPT_REGION_SNAPSHOT_ID, 0);
7050        if (err)
7051                return err;
7052
7053        pr_out_section_start(dl, "dump");
7054        err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_region_read_cb, dl);
7055        pr_out_section_end(dl);
7056        if (!dl->json_output)
7057                pr_out("\n");
7058        return err;
7059}
7060
7061static int cmd_region_read(struct dl *dl)
7062{
7063        struct nlmsghdr *nlh;
7064        int err;
7065
7066        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_READ,
7067                               NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
7068
7069        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION |
7070                                DL_OPT_REGION_ADDRESS | DL_OPT_REGION_LENGTH |
7071                                DL_OPT_REGION_SNAPSHOT_ID, 0);
7072        if (err)
7073                return err;
7074
7075        pr_out_section_start(dl, "read");
7076        err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_region_read_cb, dl);
7077        pr_out_section_end(dl);
7078        if (!dl->json_output)
7079                pr_out("\n");
7080        return err;
7081}
7082
7083static int cmd_region_snapshot_new_cb(const struct nlmsghdr *nlh, void *data)
7084{
7085        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
7086        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
7087        struct dl *dl = data;
7088
7089        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
7090        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
7091            !tb[DEVLINK_ATTR_REGION_NAME] ||
7092            !tb[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
7093                return MNL_CB_ERROR;
7094
7095        pr_out_region(dl, tb);
7096
7097        return MNL_CB_OK;
7098}
7099
7100static int cmd_region_snapshot_new(struct dl *dl)
7101{
7102        struct nlmsghdr *nlh;
7103        int err;
7104
7105        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_NEW,
7106                               NLM_F_REQUEST | NLM_F_ACK);
7107
7108        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION,
7109                                DL_OPT_REGION_SNAPSHOT_ID);
7110        if (err)
7111                return err;
7112
7113        pr_out_section_start(dl, "regions");
7114        err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_region_snapshot_new_cb, dl);
7115        pr_out_section_end(dl);
7116        return err;
7117}
7118
7119static void cmd_region_help(void)
7120{
7121        pr_err("Usage: devlink region show [ DEV/REGION ]\n");
7122        pr_err("       devlink region del DEV/REGION snapshot SNAPSHOT_ID\n");
7123        pr_err("       devlink region new DEV/REGION snapshot SNAPSHOT_ID\n");
7124        pr_err("       devlink region dump DEV/REGION [ snapshot SNAPSHOT_ID ]\n");
7125        pr_err("       devlink region read DEV/REGION [ snapshot SNAPSHOT_ID ] address ADDRESS length LENGTH\n");
7126}
7127
7128static int cmd_region(struct dl *dl)
7129{
7130        if (dl_no_arg(dl)) {
7131                return cmd_region_show(dl);
7132        } else if (dl_argv_match(dl, "help")) {
7133                cmd_region_help();
7134                return 0;
7135        } else if (dl_argv_match(dl, "show")) {
7136                dl_arg_inc(dl);
7137                return cmd_region_show(dl);
7138        } else if (dl_argv_match(dl, "del")) {
7139                dl_arg_inc(dl);
7140                return cmd_region_snapshot_del(dl);
7141        } else if (dl_argv_match(dl, "dump")) {
7142                dl_arg_inc(dl);
7143                return cmd_region_dump(dl);
7144        } else if (dl_argv_match(dl, "read")) {
7145                dl_arg_inc(dl);
7146                return cmd_region_read(dl);
7147        } else if (dl_argv_match(dl, "new")) {
7148                dl_arg_inc(dl);
7149                return cmd_region_snapshot_new(dl);
7150        }
7151        pr_err("Command \"%s\" not found\n", dl_argv(dl));
7152        return -ENOENT;
7153}
7154
7155static int cmd_health_set_params(struct dl *dl)
7156{
7157        struct nlmsghdr *nlh;
7158        int err;
7159
7160        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_SET,
7161                               NLM_F_REQUEST | NLM_F_ACK);
7162        err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_HANDLEP | DL_OPT_HEALTH_REPORTER_NAME,
7163                            DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD |
7164                            DL_OPT_HEALTH_REPORTER_AUTO_RECOVER |
7165                            DL_OPT_HEALTH_REPORTER_AUTO_DUMP);
7166        if (err)
7167                return err;
7168
7169        dl_opts_put(nlh, dl);
7170        return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
7171}
7172
7173static int cmd_health_dump_clear(struct dl *dl)
7174{
7175        struct nlmsghdr *nlh;
7176        int err;
7177
7178        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR,
7179                               NLM_F_REQUEST | NLM_F_ACK);
7180
7181        err = dl_argv_parse_put(nlh, dl,
7182                                DL_OPT_HANDLE | DL_OPT_HANDLEP |
7183                                DL_OPT_HEALTH_REPORTER_NAME, 0);
7184        if (err)
7185                return err;
7186
7187        dl_opts_put(nlh, dl);
7188        return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
7189}
7190
7191static int fmsg_value_show(struct dl *dl, int type, struct nlattr *nl_data)
7192{
7193        uint8_t *data;
7194        uint32_t len;
7195
7196        check_indent_newline(dl);
7197        switch (type) {
7198        case MNL_TYPE_FLAG:
7199                print_bool(PRINT_ANY, NULL, "%s", mnl_attr_get_u8(nl_data));
7200                break;
7201        case MNL_TYPE_U8:
7202                print_uint(PRINT_ANY, NULL, "%u", mnl_attr_get_u8(nl_data));
7203                break;
7204        case MNL_TYPE_U16:
7205                print_uint(PRINT_ANY, NULL, "%u", mnl_attr_get_u16(nl_data));
7206                break;
7207        case MNL_TYPE_U32:
7208                print_uint(PRINT_ANY, NULL, "%u", mnl_attr_get_u32(nl_data));
7209                break;
7210        case MNL_TYPE_U64:
7211                print_u64(PRINT_ANY, NULL, "%"PRIu64, mnl_attr_get_u64(nl_data));
7212                break;
7213        case MNL_TYPE_NUL_STRING:
7214                print_string(PRINT_ANY, NULL, "%s", mnl_attr_get_str(nl_data));
7215                break;
7216        case MNL_TYPE_BINARY:
7217                len = mnl_attr_get_payload_len(nl_data);
7218                data = mnl_attr_get_payload(nl_data);
7219                pr_out_binary_value(dl, data, len);
7220                break;
7221        default:
7222                return -EINVAL;
7223        }
7224        return MNL_CB_OK;
7225}
7226
7227static void pr_out_fmsg_name(struct dl *dl, char **name)
7228{
7229        if (!*name)
7230                return;
7231
7232        pr_out_name(dl, *name);
7233        free(*name);
7234        *name = NULL;
7235}
7236
7237struct nest_entry {
7238        int attr_type;
7239        struct list_head list;
7240};
7241
7242struct fmsg_cb_data {
7243        char *name;
7244        struct dl *dl;
7245        uint8_t value_type;
7246        struct list_head entry_list;
7247};
7248
7249static int cmd_fmsg_nest_queue(struct fmsg_cb_data *fmsg_data,
7250                               uint8_t *attr_value, bool insert)
7251{
7252        struct nest_entry *entry;
7253
7254        if (insert) {
7255                entry = malloc(sizeof(struct nest_entry));
7256                if (!entry)
7257                        return -ENOMEM;
7258
7259                entry->attr_type = *attr_value;
7260                list_add(&entry->list, &fmsg_data->entry_list);
7261        } else {
7262                if (list_empty(&fmsg_data->entry_list))
7263                        return MNL_CB_ERROR;
7264                entry = list_first_entry(&fmsg_data->entry_list,
7265                                         struct nest_entry, list);
7266                *attr_value = entry->attr_type;
7267                list_del(&entry->list);
7268                free(entry);
7269        }
7270        return MNL_CB_OK;
7271}
7272
7273static void pr_out_fmsg_group_start(struct dl *dl, char **name)
7274{
7275        __pr_out_newline();
7276        pr_out_fmsg_name(dl, name);
7277        __pr_out_newline();
7278        __pr_out_indent_inc();
7279}
7280
7281static void pr_out_fmsg_group_end(struct dl *dl)
7282{
7283        __pr_out_newline();
7284        __pr_out_indent_dec();
7285}
7286
7287static void pr_out_fmsg_start_object(struct dl *dl, char **name)
7288{
7289        if (dl->json_output) {
7290                pr_out_fmsg_name(dl, name);
7291                open_json_object(NULL);
7292        } else {
7293                pr_out_fmsg_group_start(dl, name);
7294        }
7295}
7296
7297static void pr_out_fmsg_end_object(struct dl *dl)
7298{
7299        if (dl->json_output)
7300                close_json_object();
7301        else
7302                pr_out_fmsg_group_end(dl);
7303}
7304
7305static void pr_out_fmsg_start_array(struct dl *dl, char **name)
7306{
7307        if (dl->json_output) {
7308                pr_out_fmsg_name(dl, name);
7309                open_json_array(PRINT_JSON, NULL);
7310        } else {
7311                pr_out_fmsg_group_start(dl, name);
7312        }
7313}
7314
7315static void pr_out_fmsg_end_array(struct dl *dl)
7316{
7317        if (dl->json_output)
7318                close_json_array(PRINT_JSON, NULL);
7319        else
7320                pr_out_fmsg_group_end(dl);
7321}
7322
7323static int cmd_fmsg_nest(struct fmsg_cb_data *fmsg_data, uint8_t nest_value,
7324                         bool start)
7325{
7326        struct dl *dl = fmsg_data->dl;
7327        uint8_t value = nest_value;
7328        int err;
7329
7330        err = cmd_fmsg_nest_queue(fmsg_data, &value, start);
7331        if (err != MNL_CB_OK)
7332                return err;
7333
7334        switch (value) {
7335        case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
7336                if (start)
7337                        pr_out_fmsg_start_object(dl, &fmsg_data->name);
7338                else
7339                        pr_out_fmsg_end_object(dl);
7340                break;
7341        case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
7342                break;
7343        case DEVLINK_ATTR_FMSG_ARR_NEST_START:
7344                if (start)
7345                        pr_out_fmsg_start_array(dl, &fmsg_data->name);
7346                else
7347                        pr_out_fmsg_end_array(dl);
7348                break;
7349        default:
7350                return -EINVAL;
7351        }
7352        return MNL_CB_OK;
7353}
7354
7355static int cmd_fmsg_object_cb(const struct nlmsghdr *nlh, void *data)
7356{
7357        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
7358        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
7359        struct fmsg_cb_data *fmsg_data = data;
7360        struct dl *dl = fmsg_data->dl;
7361        struct nlattr *nla_object;
7362        int attr_type;
7363        int err;
7364
7365        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
7366        if (!tb[DEVLINK_ATTR_FMSG])
7367                return MNL_CB_ERROR;
7368
7369        mnl_attr_for_each_nested(nla_object, tb[DEVLINK_ATTR_FMSG]) {
7370                attr_type = mnl_attr_get_type(nla_object);
7371                switch (attr_type) {
7372                case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
7373                case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
7374                case DEVLINK_ATTR_FMSG_ARR_NEST_START:
7375                        err = cmd_fmsg_nest(fmsg_data, attr_type, true);
7376                        if (err != MNL_CB_OK)
7377                                return err;
7378                        break;
7379                case DEVLINK_ATTR_FMSG_NEST_END:
7380                        err = cmd_fmsg_nest(fmsg_data, attr_type, false);
7381                        if (err != MNL_CB_OK)
7382                                return err;
7383                        break;
7384                case DEVLINK_ATTR_FMSG_OBJ_NAME:
7385                        free(fmsg_data->name);
7386                        fmsg_data->name = strdup(mnl_attr_get_str(nla_object));
7387                        if (!fmsg_data->name)
7388                                return -ENOMEM;
7389                        break;
7390                case DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE:
7391                        fmsg_data->value_type = mnl_attr_get_u8(nla_object);
7392                        break;
7393                case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA:
7394                        pr_out_fmsg_name(dl, &fmsg_data->name);
7395                        err = fmsg_value_show(dl, fmsg_data->value_type,
7396                                              nla_object);
7397                        if (err != MNL_CB_OK)
7398                                return err;
7399                        break;
7400                default:
7401                        return -EINVAL;
7402                }
7403        }
7404        return MNL_CB_OK;
7405}
7406
7407static void cmd_fmsg_init(struct dl *dl, struct fmsg_cb_data *data)
7408{
7409        /* FMSG is dynamic: opening of an object or array causes a
7410         * newline. JSON starts with an { or [, but plain text should
7411         * not start with a new line. Ensure this by setting
7412         * g_new_line_count to 1: avoiding newline before the first
7413         * print.
7414         */
7415        g_new_line_count = 1;
7416        data->name = NULL;
7417        data->dl = dl;
7418        INIT_LIST_HEAD(&data->entry_list);
7419}
7420
7421static int cmd_health_object_common(struct dl *dl, uint8_t cmd, uint16_t flags)
7422{
7423        struct fmsg_cb_data data;
7424        struct nlmsghdr *nlh;
7425        int err;
7426
7427        nlh = mnlg_msg_prepare(dl->nlg, cmd, flags | NLM_F_REQUEST | NLM_F_ACK);
7428
7429        err = dl_argv_parse_put(nlh, dl,
7430                                DL_OPT_HANDLE | DL_OPT_HANDLEP |
7431                                DL_OPT_HEALTH_REPORTER_NAME, 0);
7432        if (err)
7433                return err;
7434
7435        cmd_fmsg_init(dl, &data);
7436        err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_fmsg_object_cb, &data);
7437        free(data.name);
7438        return err;
7439}
7440
7441static int cmd_health_dump_show(struct dl *dl)
7442{
7443        return cmd_health_object_common(dl,
7444                                        DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,
7445                                        NLM_F_DUMP);
7446}
7447
7448static int cmd_health_diagnose(struct dl *dl)
7449{
7450        return cmd_health_object_common(dl,
7451                                        DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE,
7452                                        0);
7453}
7454
7455static int cmd_health_test(struct dl *dl)
7456{
7457        return cmd_health_object_common(dl,
7458                                        DEVLINK_CMD_HEALTH_REPORTER_TEST,
7459                                        0);
7460}
7461
7462static int cmd_health_recover(struct dl *dl)
7463{
7464        struct nlmsghdr *nlh;
7465        int err;
7466
7467        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_RECOVER,
7468                               NLM_F_REQUEST | NLM_F_ACK);
7469
7470        err = dl_argv_parse_put(nlh, dl,
7471                                DL_OPT_HANDLE | DL_OPT_HANDLEP |
7472                                DL_OPT_HEALTH_REPORTER_NAME, 0);
7473        if (err)
7474                return err;
7475
7476        dl_opts_put(nlh, dl);
7477        return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
7478}
7479
7480enum devlink_health_reporter_state {
7481        DEVLINK_HEALTH_REPORTER_STATE_HEALTHY,
7482        DEVLINK_HEALTH_REPORTER_STATE_ERROR,
7483};
7484
7485static const char *health_state_name(uint8_t state)
7486{
7487        switch (state) {
7488        case DEVLINK_HEALTH_REPORTER_STATE_HEALTHY:
7489                return HEALTH_REPORTER_STATE_HEALTHY_STR;
7490        case DEVLINK_HEALTH_REPORTER_STATE_ERROR:
7491                return HEALTH_REPORTER_STATE_ERROR_STR;
7492        default:
7493                return "<unknown state>";
7494        }
7495}
7496
7497static void pr_out_dump_reporter_format_logtime(struct dl *dl, const struct nlattr *attr)
7498{
7499        char dump_date[HEALTH_REPORTER_TIMESTAMP_FMT_LEN];
7500        char dump_time[HEALTH_REPORTER_TIMESTAMP_FMT_LEN];
7501        uint64_t time_ms = mnl_attr_get_u64(attr);
7502        struct sysinfo s_info;
7503        struct tm *info;
7504        time_t now, sec;
7505        int err;
7506
7507        time(&now);
7508        info = localtime(&now);
7509        err = sysinfo(&s_info);
7510        if (err)
7511                goto out;
7512        /* Subtract uptime in sec from now yields the time of system
7513         * uptime. To this, add time_ms which is the amount of
7514         * milliseconds elapsed between uptime and the dump taken.
7515         */
7516        sec = now - s_info.uptime + time_ms / 1000;
7517        info = localtime(&sec);
7518out:
7519        strftime(dump_date, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%Y-%m-%d", info);
7520        strftime(dump_time, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%H:%M:%S", info);
7521        check_indent_newline(dl);
7522        print_string(PRINT_ANY, "last_dump_date", "last_dump_date %s", dump_date);
7523        print_string(PRINT_ANY, "last_dump_time", " last_dump_time %s", dump_time);
7524}
7525
7526static void pr_out_dump_report_timestamp(struct dl *dl, const struct nlattr *attr)
7527{
7528        char dump_date[HEALTH_REPORTER_TIMESTAMP_FMT_LEN];
7529        char dump_time[HEALTH_REPORTER_TIMESTAMP_FMT_LEN];
7530        time_t tv_sec;
7531        struct tm *tm;
7532        uint64_t ts;
7533
7534        ts = mnl_attr_get_u64(attr);
7535        tv_sec = ts / 1000000000;
7536        tm = localtime(&tv_sec);
7537
7538        strftime(dump_date, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%Y-%m-%d", tm);
7539        strftime(dump_time, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%H:%M:%S", tm);
7540
7541        check_indent_newline(dl);
7542        print_string(PRINT_ANY, "last_dump_date", "last_dump_date %s", dump_date);
7543        print_string(PRINT_ANY, "last_dump_time", " last_dump_time %s", dump_time);
7544}
7545
7546static void pr_out_health(struct dl *dl, struct nlattr **tb_health,
7547                          bool print_device, bool print_port)
7548{
7549        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
7550        enum devlink_health_reporter_state state;
7551        int err;
7552
7553        err = mnl_attr_parse_nested(tb_health[DEVLINK_ATTR_HEALTH_REPORTER],
7554                                    attr_cb, tb);
7555        if (err != MNL_CB_OK)
7556                return;
7557
7558        if (!tb[DEVLINK_ATTR_HEALTH_REPORTER_NAME] ||
7559            !tb[DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT] ||
7560            !tb[DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT] ||
7561            !tb[DEVLINK_ATTR_HEALTH_REPORTER_STATE])
7562                return;
7563
7564        if (!print_device && !print_port)
7565                return;
7566        if (print_port) {
7567                if (!print_device && !tb_health[DEVLINK_ATTR_PORT_INDEX])
7568                        return;
7569                else if (tb_health[DEVLINK_ATTR_PORT_INDEX])
7570                        pr_out_port_handle_start_arr(dl, tb_health, false);
7571        }
7572        if (print_device) {
7573                if (!print_port && tb_health[DEVLINK_ATTR_PORT_INDEX])
7574                        return;
7575                else if (!tb_health[DEVLINK_ATTR_PORT_INDEX])
7576                        pr_out_handle_start_arr(dl, tb_health);
7577        }
7578
7579        check_indent_newline(dl);
7580        print_string(PRINT_ANY, "reporter", "reporter %s",
7581                     mnl_attr_get_str(tb[DEVLINK_ATTR_HEALTH_REPORTER_NAME]));
7582        if (!dl->json_output) {
7583                __pr_out_newline();
7584                __pr_out_indent_inc();
7585        }
7586        state = mnl_attr_get_u8(tb[DEVLINK_ATTR_HEALTH_REPORTER_STATE]);
7587        check_indent_newline(dl);
7588        print_string(PRINT_ANY, "state", "state %s", health_state_name(state));
7589        pr_out_u64(dl, "error",
7590                   mnl_attr_get_u64(tb[DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT]));
7591        pr_out_u64(dl, "recover",
7592                   mnl_attr_get_u64(tb[DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT]));
7593        if (tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS])
7594                pr_out_dump_report_timestamp(dl, tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS]);
7595        else if (tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS])
7596                pr_out_dump_reporter_format_logtime(dl, tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS]);
7597        if (tb[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD])
7598                pr_out_u64(dl, "grace_period",
7599                           mnl_attr_get_u64(tb[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]));
7600        if (tb[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])
7601                print_bool(PRINT_ANY, "auto_recover", " auto_recover %s",
7602                           mnl_attr_get_u8(tb[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]));
7603        if (tb[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP])
7604                print_bool(PRINT_ANY, "auto_dump", " auto_dump %s",
7605                           mnl_attr_get_u8(tb[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]));
7606
7607        __pr_out_indent_dec();
7608        pr_out_handle_end(dl);
7609}
7610
7611struct health_ctx {
7612        struct dl *dl;
7613        bool show_device;
7614        bool show_port;
7615};
7616
7617static int cmd_health_show_cb(const struct nlmsghdr *nlh, void *data)
7618{
7619        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
7620        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
7621        struct health_ctx *ctx = data;
7622        struct dl *dl = ctx->dl;
7623
7624        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
7625        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
7626            !tb[DEVLINK_ATTR_HEALTH_REPORTER])
7627                return MNL_CB_ERROR;
7628
7629        pr_out_health(dl, tb, ctx->show_device, ctx->show_port);
7630
7631        return MNL_CB_OK;
7632}
7633
7634static int __cmd_health_show(struct dl *dl, bool show_device, bool show_port)
7635{
7636        struct nlmsghdr *nlh;
7637        struct health_ctx ctx = { dl, show_device, show_port };
7638        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
7639        int err;
7640
7641        if (dl_argc(dl) == 0)
7642                flags |= NLM_F_DUMP;
7643        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_GET,
7644                               flags);
7645
7646        if (dl_argc(dl) > 0) {
7647                ctx.show_port = true;
7648                err = dl_argv_parse_put(nlh, dl,
7649                                        DL_OPT_HANDLE | DL_OPT_HANDLEP |
7650                                        DL_OPT_HEALTH_REPORTER_NAME, 0);
7651                if (err)
7652                        return err;
7653        }
7654        pr_out_section_start(dl, "health");
7655
7656        err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_health_show_cb, &ctx);
7657        pr_out_section_end(dl);
7658        return err;
7659}
7660
7661static void cmd_health_help(void)
7662{
7663        pr_err("Usage: devlink health show [ { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME ]\n");
7664        pr_err("       devlink health recover { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME\n");
7665        pr_err("       devlink health diagnose { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME\n");
7666        pr_err("       devlink health test { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME\n");
7667        pr_err("       devlink health dump show { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME\n");
7668        pr_err("       devlink health dump clear { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME\n");
7669        pr_err("       devlink health set { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME\n");
7670        pr_err("                          [ grace_period MSEC ]\n");
7671        pr_err("                          [ auto_recover { true | false } ]\n");
7672        pr_err("                          [ auto_dump    { true | false } ]\n");
7673}
7674
7675static int cmd_health(struct dl *dl)
7676{
7677        if (dl_argv_match(dl, "help")) {
7678                cmd_health_help();
7679                return 0;
7680        } else if (dl_argv_match(dl, "show") ||
7681                   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
7682                dl_arg_inc(dl);
7683                return __cmd_health_show(dl, true, true);
7684        } else if (dl_argv_match(dl, "recover")) {
7685                dl_arg_inc(dl);
7686                return cmd_health_recover(dl);
7687        } else if (dl_argv_match(dl, "diagnose")) {
7688                dl_arg_inc(dl);
7689                return cmd_health_diagnose(dl);
7690        } else if (dl_argv_match(dl, "test")) {
7691                dl_arg_inc(dl);
7692                return cmd_health_test(dl);
7693        } else if (dl_argv_match(dl, "dump")) {
7694                dl_arg_inc(dl);
7695                if (dl_argv_match(dl, "show")) {
7696                        dl_arg_inc(dl);
7697                        return cmd_health_dump_show(dl);
7698                } else if (dl_argv_match(dl, "clear")) {
7699                        dl_arg_inc(dl);
7700                        return cmd_health_dump_clear(dl);
7701                }
7702        } else if (dl_argv_match(dl, "set")) {
7703                dl_arg_inc(dl);
7704                return cmd_health_set_params(dl);
7705        }
7706        pr_err("Command \"%s\" not found\n", dl_argv(dl));
7707        return -ENOENT;
7708}
7709
7710static const char *trap_type_name(uint8_t type)
7711{
7712        switch (type) {
7713        case DEVLINK_TRAP_TYPE_DROP:
7714                return "drop";
7715        case DEVLINK_TRAP_TYPE_EXCEPTION:
7716                return "exception";
7717        case DEVLINK_TRAP_TYPE_CONTROL:
7718                return "control";
7719        default:
7720                return "<unknown type>";
7721        }
7722}
7723
7724static const char *trap_action_name(uint8_t action)
7725{
7726        switch (action) {
7727        case DEVLINK_TRAP_ACTION_DROP:
7728                return "drop";
7729        case DEVLINK_TRAP_ACTION_TRAP:
7730                return "trap";
7731        case DEVLINK_TRAP_ACTION_MIRROR:
7732                return "mirror";
7733        default:
7734                return "<unknown action>";
7735        }
7736}
7737
7738static const char *trap_metadata_name(const struct nlattr *attr)
7739{
7740        switch (attr->nla_type) {
7741        case DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT:
7742                return "input_port";
7743        case DEVLINK_ATTR_TRAP_METADATA_TYPE_FA_COOKIE:
7744                return "flow_action_cookie";
7745        default:
7746                return "<unknown metadata type>";
7747        }
7748}
7749static void pr_out_trap_metadata(struct dl *dl, struct nlattr *attr)
7750{
7751        struct nlattr *attr_metadata;
7752
7753        pr_out_array_start(dl, "metadata");
7754        mnl_attr_for_each_nested(attr_metadata, attr) {
7755                check_indent_newline(dl);
7756                print_string(PRINT_ANY, NULL, "%s",
7757                             trap_metadata_name(attr_metadata));
7758        }
7759        pr_out_array_end(dl);
7760}
7761
7762static void pr_out_trap(struct dl *dl, struct nlattr **tb, bool array)
7763{
7764        uint8_t action = mnl_attr_get_u8(tb[DEVLINK_ATTR_TRAP_ACTION]);
7765        uint8_t type = mnl_attr_get_u8(tb[DEVLINK_ATTR_TRAP_TYPE]);
7766
7767        if (array)
7768                pr_out_handle_start_arr(dl, tb);
7769        else
7770                __pr_out_handle_start(dl, tb, true, false);
7771
7772        check_indent_newline(dl);
7773        print_string(PRINT_ANY, "name", "name %s",
7774                     mnl_attr_get_str(tb[DEVLINK_ATTR_TRAP_NAME]));
7775        print_string(PRINT_ANY, "type", " type %s", trap_type_name(type));
7776        print_bool(PRINT_ANY, "generic", " generic %s", !!tb[DEVLINK_ATTR_TRAP_GENERIC]);
7777        print_string(PRINT_ANY, "action", " action %s", trap_action_name(action));
7778        print_string(PRINT_ANY, "group", " group %s",
7779                     mnl_attr_get_str(tb[DEVLINK_ATTR_TRAP_GROUP_NAME]));
7780        if (dl->verbose)
7781                pr_out_trap_metadata(dl, tb[DEVLINK_ATTR_TRAP_METADATA]);
7782        pr_out_stats(dl, tb[DEVLINK_ATTR_STATS]);
7783        pr_out_handle_end(dl);
7784}
7785
7786static int cmd_trap_show_cb(const struct nlmsghdr *nlh, void *data)
7787{
7788        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
7789        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
7790        struct dl *dl = data;
7791
7792        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
7793        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
7794            !tb[DEVLINK_ATTR_TRAP_NAME] || !tb[DEVLINK_ATTR_TRAP_TYPE] ||
7795            !tb[DEVLINK_ATTR_TRAP_ACTION] ||
7796            !tb[DEVLINK_ATTR_TRAP_GROUP_NAME] ||
7797            !tb[DEVLINK_ATTR_TRAP_METADATA] || !tb[DEVLINK_ATTR_STATS])
7798                return MNL_CB_ERROR;
7799
7800        pr_out_trap(dl, tb, true);
7801
7802        return MNL_CB_OK;
7803}
7804
7805static void cmd_trap_help(void)
7806{
7807        pr_err("Usage: devlink trap set DEV trap TRAP [ action { trap | drop | mirror } ]\n");
7808        pr_err("       devlink trap show [ DEV trap TRAP ]\n");
7809        pr_err("       devlink trap group set DEV group GROUP [ action { trap | drop | mirror } ]\n");
7810        pr_err("                              [ policer POLICER ] [ nopolicer ]\n");
7811        pr_err("       devlink trap group show [ DEV group GROUP ]\n");
7812        pr_err("       devlink trap policer set DEV policer POLICER [ rate RATE ] [ burst BURST ]\n");
7813        pr_err("       devlink trap policer show DEV policer POLICER\n");
7814}
7815
7816static int cmd_trap_show(struct dl *dl)
7817{
7818        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
7819        struct nlmsghdr *nlh;
7820        int err;
7821
7822        if (dl_argc(dl) == 0)
7823                flags |= NLM_F_DUMP;
7824
7825        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_TRAP_GET, flags);
7826
7827        if (dl_argc(dl) > 0) {
7828                err = dl_argv_parse_put(nlh, dl,
7829                                        DL_OPT_HANDLE | DL_OPT_TRAP_NAME, 0);
7830                if (err)
7831                        return err;
7832        }
7833
7834        pr_out_section_start(dl, "trap");
7835        err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_trap_show_cb, dl);
7836        pr_out_section_end(dl);
7837
7838        return err;
7839}
7840
7841static int cmd_trap_set(struct dl *dl)
7842{
7843        struct nlmsghdr *nlh;
7844        int err;
7845
7846        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_TRAP_SET,
7847                               NLM_F_REQUEST | NLM_F_ACK);
7848
7849        err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_TRAP_NAME,
7850                                DL_OPT_TRAP_ACTION);
7851        if (err)
7852                return err;
7853
7854        return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
7855}
7856
7857static void pr_out_trap_group(struct dl *dl, struct nlattr **tb, bool array)
7858{
7859        if (array)
7860                pr_out_handle_start_arr(dl, tb);
7861        else
7862                __pr_out_handle_start(dl, tb, true, false);
7863
7864        check_indent_newline(dl);
7865        print_string(PRINT_ANY, "name", "name %s",
7866                     mnl_attr_get_str(tb[DEVLINK_ATTR_TRAP_GROUP_NAME]));
7867        print_bool(PRINT_ANY, "generic", " generic %s", !!tb[DEVLINK_ATTR_TRAP_GENERIC]);
7868        if (tb[DEVLINK_ATTR_TRAP_POLICER_ID])
7869                print_uint(PRINT_ANY, "policer", " policer %u",
7870                           mnl_attr_get_u32(tb[DEVLINK_ATTR_TRAP_POLICER_ID]));
7871        pr_out_stats(dl, tb[DEVLINK_ATTR_STATS]);
7872        pr_out_handle_end(dl);
7873}
7874
7875static int cmd_trap_group_show_cb(const struct nlmsghdr *nlh, void *data)
7876{
7877        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
7878        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
7879        struct dl *dl = data;
7880
7881        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
7882        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
7883            !tb[DEVLINK_ATTR_TRAP_GROUP_NAME] || !tb[DEVLINK_ATTR_STATS])
7884                return MNL_CB_ERROR;
7885
7886        pr_out_trap_group(dl, tb, true);
7887
7888        return MNL_CB_OK;
7889}
7890
7891static int cmd_trap_group_show(struct dl *dl)
7892{
7893        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
7894        struct nlmsghdr *nlh;
7895        int err;
7896
7897        if (dl_argc(dl) == 0)
7898                flags |= NLM_F_DUMP;
7899
7900        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_TRAP_GROUP_GET, flags);
7901
7902        if (dl_argc(dl) > 0) {
7903                err = dl_argv_parse_put(nlh, dl,
7904                                        DL_OPT_HANDLE | DL_OPT_TRAP_GROUP_NAME,
7905                                        0);
7906                if (err)
7907                        return err;
7908        }
7909
7910        pr_out_section_start(dl, "trap_group");
7911        err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_trap_group_show_cb, dl);
7912        pr_out_section_end(dl);
7913
7914        return err;
7915}
7916
7917static int cmd_trap_group_set(struct dl *dl)
7918{
7919        struct nlmsghdr *nlh;
7920        int err;
7921
7922        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_TRAP_GROUP_SET,
7923                               NLM_F_REQUEST | NLM_F_ACK);
7924
7925        err = dl_argv_parse_put(nlh, dl,
7926                                DL_OPT_HANDLE | DL_OPT_TRAP_GROUP_NAME,
7927                                DL_OPT_TRAP_ACTION | DL_OPT_TRAP_POLICER_ID);
7928        if (err)
7929                return err;
7930
7931        return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
7932}
7933
7934static int cmd_trap_group(struct dl *dl)
7935{
7936        if (dl_argv_match(dl, "help")) {
7937                cmd_trap_help();
7938                return 0;
7939        } else if (dl_argv_match(dl, "show") ||
7940                   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
7941                dl_arg_inc(dl);
7942                return cmd_trap_group_show(dl);
7943        } else if (dl_argv_match(dl, "set")) {
7944                dl_arg_inc(dl);
7945                return cmd_trap_group_set(dl);
7946        }
7947        pr_err("Command \"%s\" not found\n", dl_argv(dl));
7948        return -ENOENT;
7949}
7950
7951static void pr_out_trap_policer(struct dl *dl, struct nlattr **tb, bool array)
7952{
7953        if (array)
7954                pr_out_handle_start_arr(dl, tb);
7955        else
7956                __pr_out_handle_start(dl, tb, true, false);
7957
7958        check_indent_newline(dl);
7959        print_uint(PRINT_ANY, "policer", "policer %u",
7960                   mnl_attr_get_u32(tb[DEVLINK_ATTR_TRAP_POLICER_ID]));
7961        print_u64(PRINT_ANY, "rate", " rate %llu",
7962                   mnl_attr_get_u64(tb[DEVLINK_ATTR_TRAP_POLICER_RATE]));
7963        print_u64(PRINT_ANY, "burst", " burst %llu",
7964                   mnl_attr_get_u64(tb[DEVLINK_ATTR_TRAP_POLICER_BURST]));
7965        if (tb[DEVLINK_ATTR_STATS])
7966                pr_out_stats(dl, tb[DEVLINK_ATTR_STATS]);
7967        pr_out_handle_end(dl);
7968}
7969
7970static int cmd_trap_policer_show_cb(const struct nlmsghdr *nlh, void *data)
7971{
7972        struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
7973        struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
7974        struct dl *dl = data;
7975
7976        mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
7977        if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
7978            !tb[DEVLINK_ATTR_TRAP_POLICER_ID] ||
7979            !tb[DEVLINK_ATTR_TRAP_POLICER_RATE] ||
7980            !tb[DEVLINK_ATTR_TRAP_POLICER_BURST])
7981                return MNL_CB_ERROR;
7982
7983        pr_out_trap_policer(dl, tb, true);
7984
7985        return MNL_CB_OK;
7986}
7987
7988static int cmd_trap_policer_show(struct dl *dl)
7989{
7990        uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
7991        struct nlmsghdr *nlh;
7992        int err;
7993
7994        if (dl_argc(dl) == 0)
7995                flags |= NLM_F_DUMP;
7996
7997        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_TRAP_POLICER_GET, flags);
7998
7999        if (dl_argc(dl) > 0) {
8000                err = dl_argv_parse_put(nlh, dl,
8001                                        DL_OPT_HANDLE | DL_OPT_TRAP_POLICER_ID,
8002                                        0);
8003                if (err)
8004                        return err;
8005        }
8006
8007        pr_out_section_start(dl, "trap_policer");
8008        err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_trap_policer_show_cb, dl);
8009        pr_out_section_end(dl);
8010
8011        return err;
8012}
8013
8014static int cmd_trap_policer_set(struct dl *dl)
8015{
8016        struct nlmsghdr *nlh;
8017        int err;
8018
8019        nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_TRAP_POLICER_SET,
8020                               NLM_F_REQUEST | NLM_F_ACK);
8021
8022        err = dl_argv_parse_put(nlh, dl,
8023                                DL_OPT_HANDLE | DL_OPT_TRAP_POLICER_ID,
8024                                DL_OPT_TRAP_POLICER_RATE |
8025                                DL_OPT_TRAP_POLICER_BURST);
8026        if (err)
8027                return err;
8028
8029        return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
8030}
8031
8032static int cmd_trap_policer(struct dl *dl)
8033{
8034        if (dl_argv_match(dl, "help")) {
8035                cmd_trap_help();
8036                return 0;
8037        } else if (dl_argv_match(dl, "show") ||
8038                   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
8039                dl_arg_inc(dl);
8040                return cmd_trap_policer_show(dl);
8041        } else if (dl_argv_match(dl, "set")) {
8042                dl_arg_inc(dl);
8043                return cmd_trap_policer_set(dl);
8044        }
8045        pr_err("Command \"%s\" not found\n", dl_argv(dl));
8046        return -ENOENT;
8047}
8048
8049static int cmd_trap(struct dl *dl)
8050{
8051        if (dl_argv_match(dl, "help")) {
8052                cmd_trap_help();
8053                return 0;
8054        } else if (dl_argv_match(dl, "show") ||
8055                   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
8056                dl_arg_inc(dl);
8057                return cmd_trap_show(dl);
8058        } else if (dl_argv_match(dl, "set")) {
8059                dl_arg_inc(dl);
8060                return cmd_trap_set(dl);
8061        } else if (dl_argv_match(dl, "group")) {
8062                dl_arg_inc(dl);
8063                return cmd_trap_group(dl);
8064        } else if (dl_argv_match(dl, "policer")) {
8065                dl_arg_inc(dl);
8066                return cmd_trap_policer(dl);
8067        }
8068        pr_err("Command \"%s\" not found\n", dl_argv(dl));
8069        return -ENOENT;
8070}
8071
8072static void help(void)
8073{
8074        pr_err("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n"
8075               "       devlink [ -f[orce] ] -b[atch] filename -N[etns] netnsname\n"
8076               "where  OBJECT := { dev | port | sb | monitor | dpipe | resource | region | health | trap }\n"
8077               "       OPTIONS := { -V[ersion] | -n[o-nice-names] | -j[son] | -p[retty] | -v[erbose] -s[tatistics] }\n");
8078}
8079
8080static int dl_cmd(struct dl *dl, int argc, char **argv)
8081{
8082        dl->argc = argc;
8083        dl->argv = argv;
8084
8085        if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
8086                help();
8087                return 0;
8088        } else if (dl_argv_match(dl, "dev")) {
8089                dl_arg_inc(dl);
8090                return cmd_dev(dl);
8091        } else if (dl_argv_match(dl, "port")) {
8092                dl_arg_inc(dl);
8093                return cmd_port(dl);
8094        } else if (dl_argv_match(dl, "sb")) {
8095                dl_arg_inc(dl);
8096                return cmd_sb(dl);
8097        } else if (dl_argv_match(dl, "monitor")) {
8098                dl_arg_inc(dl);
8099                return cmd_mon(dl);
8100        } else if (dl_argv_match(dl, "dpipe")) {
8101                dl_arg_inc(dl);
8102                return cmd_dpipe(dl);
8103        } else if (dl_argv_match(dl, "resource")) {
8104                dl_arg_inc(dl);
8105                return cmd_resource(dl);
8106        } else if (dl_argv_match(dl, "region")) {
8107                dl_arg_inc(dl);
8108                return cmd_region(dl);
8109        } else if (dl_argv_match(dl, "health")) {
8110                dl_arg_inc(dl);
8111                return cmd_health(dl);
8112        } else if (dl_argv_match(dl, "trap")) {
8113                dl_arg_inc(dl);
8114                return cmd_trap(dl);
8115        }
8116        pr_err("Object \"%s\" not found\n", dl_argv(dl));
8117        return -ENOENT;
8118}
8119
8120static int dl_init(struct dl *dl)
8121{
8122        int err;
8123
8124        dl->nlg = mnlg_socket_open(DEVLINK_GENL_NAME, DEVLINK_GENL_VERSION);
8125        if (!dl->nlg) {
8126                pr_err("Failed to connect to devlink Netlink\n");
8127                return -errno;
8128        }
8129
8130        err = ifname_map_init(dl);
8131        if (err) {
8132                pr_err("Failed to create index map\n");
8133                goto err_ifname_map_create;
8134        }
8135        new_json_obj_plain(dl->json_output);
8136        return 0;
8137
8138err_ifname_map_create:
8139        mnlg_socket_close(dl->nlg);
8140        return err;
8141}
8142
8143static void dl_fini(struct dl *dl)
8144{
8145        delete_json_obj_plain();
8146        ifname_map_fini(dl);
8147        mnlg_socket_close(dl->nlg);
8148}
8149
8150static struct dl *dl_alloc(void)
8151{
8152        struct dl *dl;
8153
8154        dl = calloc(1, sizeof(*dl));
8155        if (!dl)
8156                return NULL;
8157        return dl;
8158}
8159
8160static void dl_free(struct dl *dl)
8161{
8162        free(dl);
8163}
8164
8165static int dl_batch_cmd(int argc, char *argv[], void *data)
8166{
8167        struct dl *dl = data;
8168
8169        return dl_cmd(dl, argc, argv);
8170}
8171
8172static int dl_batch(struct dl *dl, const char *name, bool force)
8173{
8174        return do_batch(name, force, dl_batch_cmd, dl);
8175}
8176
8177int main(int argc, char **argv)
8178{
8179        static const struct option long_options[] = {
8180                { "Version",            no_argument,            NULL, 'V' },
8181                { "force",              no_argument,            NULL, 'f' },
8182                { "batch",              required_argument,      NULL, 'b' },
8183                { "no-nice-names",      no_argument,            NULL, 'n' },
8184                { "json",               no_argument,            NULL, 'j' },
8185                { "pretty",             no_argument,            NULL, 'p' },
8186                { "verbose",            no_argument,            NULL, 'v' },
8187                { "statistics",         no_argument,            NULL, 's' },
8188                { "Netns",              required_argument,      NULL, 'N' },
8189                { NULL, 0, NULL, 0 }
8190        };
8191        const char *batch_file = NULL;
8192        bool force = false;
8193        struct dl *dl;
8194        int opt;
8195        int err;
8196        int ret;
8197
8198        dl = dl_alloc();
8199        if (!dl) {
8200                pr_err("Failed to allocate memory for devlink\n");
8201                return EXIT_FAILURE;
8202        }
8203
8204        while ((opt = getopt_long(argc, argv, "Vfb:njpvsN:",
8205                                  long_options, NULL)) >= 0) {
8206
8207                switch (opt) {
8208                case 'V':
8209                        printf("devlink utility, iproute2-%s\n", version);
8210                        ret = EXIT_SUCCESS;
8211                        goto dl_free;
8212                case 'f':
8213                        force = true;
8214                        break;
8215                case 'b':
8216                        batch_file = optarg;
8217                        break;
8218                case 'n':
8219                        dl->no_nice_names = true;
8220                        break;
8221                case 'j':
8222                        dl->json_output = true;
8223                        break;
8224                case 'p':
8225                        pretty = true;
8226                        break;
8227                case 'v':
8228                        dl->verbose = true;
8229                        break;
8230                case 's':
8231                        dl->stats = true;
8232                        break;
8233                case 'N':
8234                        if (netns_switch(optarg)) {
8235                                ret = EXIT_FAILURE;
8236                                goto dl_free;
8237                        }
8238                        break;
8239                default:
8240                        pr_err("Unknown option.\n");
8241                        help();
8242                        ret = EXIT_FAILURE;
8243                        goto dl_free;
8244                }
8245        }
8246
8247        argc -= optind;
8248        argv += optind;
8249
8250        err = dl_init(dl);
8251        if (err) {
8252                ret = EXIT_FAILURE;
8253                goto dl_free;
8254        }
8255
8256        if (batch_file)
8257                err = dl_batch(dl, batch_file, force);
8258        else
8259                err = dl_cmd(dl, argc, argv);
8260
8261        if (err) {
8262                ret = EXIT_FAILURE;
8263                goto dl_fini;
8264        }
8265
8266        ret = EXIT_SUCCESS;
8267
8268dl_fini:
8269        dl_fini(dl);
8270dl_free:
8271        dl_free(dl);
8272
8273        return ret;
8274}
8275