#include <limits.h>
#include <errno.h>
#include <inttypes.h>
+#include <sys/sysinfo.h>
+#define _LINUX_SYSINFO_H /* avoid collision with musl header */
#include <linux/genetlink.h>
#include <linux/devlink.h>
#include <libmnl/libmnl.h>
#include <netinet/ether.h>
-#include <sys/sysinfo.h>
-#include <sys/queue.h>
+#include <sys/types.h>
#include "SNAPSHOT.h"
#include "list.h"
#include "mnlg.h"
#include "json_writer.h"
#include "utils.h"
+#include "namespace.h"
#define ESWITCH_MODE_LEGACY "legacy"
#define ESWITCH_MODE_SWITCHDEV "switchdev"
g_new_line_count = 0; \
}
+static void __attribute__((format(printf, 1, 2)))
+pr_out_tty(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (!isatty(STDOUT_FILENO))
+ return;
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+}
+
static void __pr_out_indent_inc(void)
{
if (g_indent_level + INDENT_STR_STEP > INDENT_STR_MAXLEN)
return 0;
}
-static int _mnlg_socket_sndrcv(struct mnlg_socket *nlg,
- const struct nlmsghdr *nlh,
- mnl_cb_t data_cb, void *data)
+static int _mnlg_socket_send(struct mnlg_socket *nlg,
+ const struct nlmsghdr *nlh)
{
int err;
pr_err("Failed to call mnlg_socket_send\n");
return -errno;
}
+ return 0;
+}
+
+static int _mnlg_socket_sndrcv(struct mnlg_socket *nlg,
+ const struct nlmsghdr *nlh,
+ mnl_cb_t data_cb, void *data)
+{
+ int err;
+
+ err = _mnlg_socket_send(nlg, nlh);
+ if (err)
+ return err;
return _mnlg_socket_recv_run(nlg, data_cb, data);
}
#define DL_OPT_FLASH_FILE_NAME BIT(25)
#define DL_OPT_FLASH_COMPONENT BIT(26)
#define DL_OPT_HEALTH_REPORTER_NAME BIT(27)
-#define DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD BIT(27)
-#define DL_OPT_HEALTH_REPORTER_AUTO_RECOVER BIT(28)
+#define DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD BIT(28)
+#define DL_OPT_HEALTH_REPORTER_AUTO_RECOVER BIT(29)
+#define DL_OPT_TRAP_NAME BIT(30)
+#define DL_OPT_TRAP_ACTION BIT(31)
+#define DL_OPT_TRAP_GROUP_NAME BIT(32)
+#define DL_OPT_NETNS BIT(33)
struct dl_opts {
- uint32_t present; /* flags of present items */
+ uint64_t present; /* flags of present items */
char *bus_name;
char *dev_name;
uint32_t port_index;
bool dpipe_counters_enable;
bool eswitch_encap_mode;
const char *resource_path;
- uint32_t resource_size;
+ uint64_t resource_size;
uint32_t resource_id;
bool resource_id_valid;
const char *param_name;
const char *reporter_name;
uint64_t reporter_graceful_period;
bool reporter_auto_recover;
+ const char *trap_name;
+ const char *trap_group_name;
+ enum devlink_trap_action trap_action;
+ bool netns_is_pid;
+ uint32_t netns;
};
struct dl {
bool json_output;
bool pretty_output;
bool verbose;
+ bool stats;
struct {
bool present;
char *bus_name;
dl->argv++;
}
+static void dl_arg_dec(struct dl *dl)
+{
+ dl->argc++;
+ dl->argv--;
+}
+
static char *dl_argv_next(struct dl *dl)
{
char *ret;
return dl_argc(dl) == 0;
}
+static void __pr_out_indent_newline(struct dl *dl)
+{
+ if (!g_indent_newline && !dl->json_output)
+ pr_out(" ");
+}
+
+static void check_indent_newline(struct dl *dl)
+{
+ __pr_out_indent_newline(dl);
+
+ if (g_indent_newline && !is_json_context()) {
+ printf("%s", g_indent_str);
+ g_indent_newline = false;
+ }
+ g_new_line_count = 0;
+}
+
static const enum mnl_attr_data_type devlink_policy[DEVLINK_ATTR_MAX + 1] = {
[DEVLINK_ATTR_BUS_NAME] = MNL_TYPE_NUL_STRING,
[DEVLINK_ATTR_DEV_NAME] = MNL_TYPE_NUL_STRING,
[DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT] = MNL_TYPE_U64,
[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS] = MNL_TYPE_U64,
[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = MNL_TYPE_U64,
+ [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT] = MNL_TYPE_STRING,
+ [DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG] = MNL_TYPE_STRING,
+ [DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE] = MNL_TYPE_U64,
+ [DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL] = MNL_TYPE_U64,
+ [DEVLINK_ATTR_STATS] = MNL_TYPE_NESTED,
+ [DEVLINK_ATTR_TRAP_NAME] = MNL_TYPE_STRING,
+ [DEVLINK_ATTR_TRAP_ACTION] = MNL_TYPE_U8,
+ [DEVLINK_ATTR_TRAP_TYPE] = MNL_TYPE_U8,
+ [DEVLINK_ATTR_TRAP_GENERIC] = MNL_TYPE_FLAG,
+ [DEVLINK_ATTR_TRAP_METADATA] = MNL_TYPE_NESTED,
+ [DEVLINK_ATTR_TRAP_GROUP_NAME] = MNL_TYPE_STRING,
+ [DEVLINK_ATTR_RELOAD_FAILED] = MNL_TYPE_U8,
+};
+
+static const enum mnl_attr_data_type
+devlink_stats_policy[DEVLINK_ATTR_STATS_MAX + 1] = {
+ [DEVLINK_ATTR_STATS_RX_PACKETS] = MNL_TYPE_U64,
+ [DEVLINK_ATTR_STATS_RX_BYTES] = MNL_TYPE_U64,
};
static int attr_cb(const struct nlattr *attr, void *data)
return MNL_CB_OK;
}
+static int attr_stats_cb(const struct nlattr *attr, void *data)
+{
+ const struct nlattr **tb = data;
+ int type;
+
+ /* Allow the tool to work on top of newer kernels that might contain
+ * more attributes.
+ */
+ if (mnl_attr_type_valid(attr, DEVLINK_ATTR_STATS_MAX) < 0)
+ return MNL_CB_OK;
+
+ type = mnl_attr_get_type(attr);
+ if (mnl_attr_validate(attr, devlink_stats_policy[type]) < 0)
+ return MNL_CB_ERROR;
+
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
static int ifname_map_cb(const struct nlmsghdr *nlh, void *data)
{
struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
static int dl_argv_handle_both(struct dl *dl, char **p_bus_name,
char **p_dev_name, uint32_t *p_port_index,
- uint32_t *p_handle_bit)
+ uint64_t *p_handle_bit)
{
char *str = dl_argv_next(dl);
unsigned int slash_count;
return 0;
}
+static int trap_action_get(const char *actionstr,
+ enum devlink_trap_action *p_action)
+{
+ if (strcmp(actionstr, "drop") == 0) {
+ *p_action = DEVLINK_TRAP_ACTION_DROP;
+ } else if (strcmp(actionstr, "trap") == 0) {
+ *p_action = DEVLINK_TRAP_ACTION_TRAP;
+ } else {
+ pr_err("Unknown trap action \"%s\"\n", actionstr);
+ return -EINVAL;
+ }
+ return 0;
+}
+
struct dl_args_metadata {
- uint32_t o_flag;
+ uint64_t o_flag;
char err_msg[DL_ARGS_REQUIRED_MAX_ERR_LEN];
};
{DL_OPT_DPIPE_TABLE_NAME, "Dpipe table name expected."},
{DL_OPT_DPIPE_TABLE_COUNTERS, "Dpipe table counter state expected."},
{DL_OPT_ESWITCH_ENCAP_MODE, "E-Switch encapsulation option expected."},
+ {DL_OPT_RESOURCE_PATH, "Resource path expected."},
+ {DL_OPT_RESOURCE_SIZE, "Resource size expected."},
{DL_OPT_PARAM_NAME, "Parameter name expected."},
{DL_OPT_PARAM_VALUE, "Value to set expected."},
{DL_OPT_PARAM_CMODE, "Configuration mode expected."},
{DL_OPT_REGION_ADDRESS, "Region address value expected."},
{DL_OPT_REGION_LENGTH, "Region length value expected."},
{DL_OPT_HEALTH_REPORTER_NAME, "Reporter's name is expected."},
+ {DL_OPT_TRAP_NAME, "Trap's name is expected."},
+ {DL_OPT_TRAP_GROUP_NAME, "Trap group's name is expected."},
};
-static int dl_args_finding_required_validate(uint32_t o_required,
- uint32_t o_found)
+static int dl_args_finding_required_validate(uint64_t o_required,
+ uint64_t o_found)
{
- uint32_t o_flag;
+ uint64_t o_flag;
int i;
for (i = 0; i < ARRAY_SIZE(dl_args_required); i++) {
return -EINVAL;
}
}
+ if (o_required & ~o_found) {
+ pr_err("BUG: unknown argument required but not found\n");
+ return -EINVAL;
+ }
return 0;
}
-static int dl_argv_parse(struct dl *dl, uint32_t o_required,
- uint32_t o_optional)
+static int dl_argv_parse(struct dl *dl, uint64_t o_required,
+ uint64_t o_optional)
{
struct dl_opts *opts = &dl->opts;
- uint32_t o_all = o_required | o_optional;
- uint32_t o_found = 0;
+ uint64_t o_all = o_required | o_optional;
+ uint64_t o_found = 0;
int err;
if (o_required & DL_OPT_HANDLE && o_required & DL_OPT_HANDLEP) {
- uint32_t handle_bit;
+ uint64_t handle_bit;
err = dl_argv_handle_both(dl, &opts->bus_name, &opts->dev_name,
&opts->port_index, &handle_bit);
if (err)
return err;
+ o_required &= ~(DL_OPT_HANDLE | DL_OPT_HANDLEP) | handle_bit;
o_found |= handle_bit;
} else if (o_required & DL_OPT_HANDLE) {
err = dl_argv_handle(dl, &opts->bus_name, &opts->dev_name);
} else if (dl_argv_match(dl, "size") &&
(o_all & DL_OPT_RESOURCE_SIZE)) {
dl_arg_inc(dl);
- err = dl_argv_uint32_t(dl, &opts->resource_size);
+ err = dl_argv_uint64_t(dl, &opts->resource_size);
if (err)
return err;
o_found |= DL_OPT_RESOURCE_SIZE;
if (err)
return err;
o_found |= DL_OPT_HEALTH_REPORTER_AUTO_RECOVER;
+ } else if (dl_argv_match(dl, "trap") &&
+ (o_all & DL_OPT_TRAP_NAME)) {
+ dl_arg_inc(dl);
+ err = dl_argv_str(dl, &opts->trap_name);
+ if (err)
+ return err;
+ o_found |= DL_OPT_TRAP_NAME;
+ } else if (dl_argv_match(dl, "group") &&
+ (o_all & DL_OPT_TRAP_GROUP_NAME)) {
+ dl_arg_inc(dl);
+ err = dl_argv_str(dl, &opts->trap_group_name);
+ if (err)
+ return err;
+ o_found |= DL_OPT_TRAP_GROUP_NAME;
+ } else if (dl_argv_match(dl, "action") &&
+ (o_all & DL_OPT_TRAP_ACTION)) {
+ const char *actionstr;
+
+ dl_arg_inc(dl);
+ err = dl_argv_str(dl, &actionstr);
+ if (err)
+ return err;
+ err = trap_action_get(actionstr, &opts->trap_action);
+ if (err)
+ return err;
+ o_found |= DL_OPT_TRAP_ACTION;
+ } else if (dl_argv_match(dl, "netns") &&
+ (o_all & DL_OPT_NETNS)) {
+ const char *netns_str;
+
+ dl_arg_inc(dl);
+ err = dl_argv_str(dl, &netns_str);
+ if (err)
+ return err;
+ opts->netns = netns_get_fd(netns_str);
+ if ((int)opts->netns < 0) {
+ dl_arg_dec(dl);
+ err = dl_argv_uint32_t(dl, &opts->netns);
+ if (err)
+ return err;
+ opts->netns_is_pid = true;
+ }
+ o_found |= DL_OPT_NETNS;
} else {
pr_err("Unknown option \"%s\"\n", dl_argv(dl));
return -EINVAL;
if (opts->present & DL_OPT_HEALTH_REPORTER_AUTO_RECOVER)
mnl_attr_put_u8(nlh, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER,
opts->reporter_auto_recover);
-
+ if (opts->present & DL_OPT_TRAP_NAME)
+ mnl_attr_put_strz(nlh, DEVLINK_ATTR_TRAP_NAME,
+ opts->trap_name);
+ if (opts->present & DL_OPT_TRAP_GROUP_NAME)
+ mnl_attr_put_strz(nlh, DEVLINK_ATTR_TRAP_GROUP_NAME,
+ opts->trap_group_name);
+ if (opts->present & DL_OPT_TRAP_ACTION)
+ mnl_attr_put_u8(nlh, DEVLINK_ATTR_TRAP_ACTION,
+ opts->trap_action);
+ if (opts->present & DL_OPT_NETNS)
+ mnl_attr_put_u32(nlh,
+ opts->netns_is_pid ? DEVLINK_ATTR_NETNS_PID :
+ DEVLINK_ATTR_NETNS_FD,
+ opts->netns);
}
static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl,
- uint32_t o_required, uint32_t o_optional)
+ uint64_t o_required, uint64_t o_optional)
{
int err;
pr_err(" devlink dev eswitch show DEV\n");
pr_err(" devlink dev param set DEV name PARAMETER value VALUE cmode { permanent | driverinit | runtime }\n");
pr_err(" devlink dev param show [DEV name PARAMETER]\n");
- pr_err(" devlink dev reload DEV\n");
+ pr_err(" devlink dev reload DEV [ netns { PID | NAME | ID } ]\n");
pr_err(" devlink dev info [ DEV ]\n");
pr_err(" devlink dev flash DEV file PATH [ component NAME ]\n");
}
if (dl->json_output) {
if (array) {
if (should_arr_last_handle_end(dl, bus_name, dev_name))
- jsonw_end_array(dl->jw);
+ close_json_array(PRINT_JSON, NULL);
if (should_arr_last_handle_start(dl, bus_name,
dev_name)) {
- jsonw_name(dl->jw, buf);
- jsonw_start_array(dl->jw);
- jsonw_start_object(dl->jw);
+ open_json_array(PRINT_JSON, buf);
+ open_json_object(NULL);
arr_last_handle_set(dl, bus_name, dev_name);
} else {
- jsonw_start_object(dl->jw);
+ open_json_object(NULL);
}
} else {
- jsonw_name(dl->jw, buf);
- jsonw_start_object(dl->jw);
+ open_json_object(buf);
}
} else {
if (array) {
static void pr_out_handle_end(struct dl *dl)
{
if (dl->json_output)
- jsonw_end_object(dl->jw);
+ close_json_object();
else
__pr_out_newline();
}
if (should_arr_last_port_handle_end(dl, bus_name,
dev_name,
port_index))
- jsonw_end_array(dl->jw);
+ close_json_array(PRINT_JSON, NULL);
if (should_arr_last_port_handle_start(dl, bus_name,
dev_name,
port_index)) {
- jsonw_name(dl->jw, buf);
- jsonw_start_array(dl->jw);
- jsonw_start_object(dl->jw);
+ open_json_array(PRINT_JSON, buf);
+ open_json_object(NULL);
arr_last_port_handle_set(dl, bus_name, dev_name,
port_index);
} else {
- jsonw_start_object(dl->jw);
+ open_json_object(NULL);
}
} else {
- jsonw_name(dl->jw, buf);
- jsonw_start_object(dl->jw);
+ open_json_object(buf);
}
} else {
pr_out("%s:", buf);
static void pr_out_port_handle_end(struct dl *dl)
{
if (dl->json_output)
- jsonw_end_object(dl->jw);
+ close_json_object();
else
pr_out("\n");
}
-
-static void pr_out_str(struct dl *dl, const char *name, const char *val)
-{
- if (dl->json_output) {
- jsonw_string_field(dl->jw, name, val);
- } else {
- if (g_indent_newline)
- pr_out("%s %s", name, val);
- else
- pr_out(" %s %s", name, val);
- }
-}
-
static void pr_out_bool(struct dl *dl, const char *name, bool val)
{
if (dl->json_output)
- jsonw_bool_field(dl->jw, name, val);
+ print_bool(PRINT_JSON, name, NULL, val);
else
- pr_out_str(dl, name, val ? "true" : "false");
+ print_string_name_value(name, val ? "true" : "false");
}
static void pr_out_uint(struct dl *dl, const char *name, unsigned int val)
{
- if (dl->json_output) {
- jsonw_uint_field(dl->jw, name, val);
- } else {
- if (g_indent_newline)
- pr_out("%s %u", name, val);
- else
- pr_out(" %s %u", name, val);
- }
+ __pr_out_indent_newline(dl);
+ if (dl->json_output)
+ print_uint(PRINT_JSON, name, NULL, val);
+ else
+ pr_out("%s %u", name, val);
}
static void pr_out_u64(struct dl *dl, const char *name, uint64_t val)
{
+ __pr_out_indent_newline(dl);
if (val == (uint64_t) -1)
- return pr_out_str(dl, name, "unlimited");
-
- if (dl->json_output) {
- jsonw_u64_field(dl->jw, name, val);
- } else {
- if (g_indent_newline)
- pr_out("%s %lu", name, val);
- else
- pr_out(" %s %lu", name, val);
- }
-}
-
-static void pr_out_bool_value(struct dl *dl, bool value)
-{
- if (dl->json_output)
- jsonw_bool(dl->jw, value);
- else
- pr_out(" %s", value ? "true" : "false");
-}
+ return print_string_name_value(name, "unlimited");
-static void pr_out_uint_value(struct dl *dl, unsigned int value)
-{
if (dl->json_output)
- jsonw_uint(dl->jw, value);
+ print_u64(PRINT_JSON, name, NULL, val);
else
- pr_out(" %u", value);
+ pr_out("%s %"PRIu64, name, val);
}
-static void pr_out_uint64_value(struct dl *dl, uint64_t value)
+static bool is_binary_eol(int i)
{
- if (dl->json_output)
- jsonw_u64(dl->jw, value);
- else
- pr_out(" %lu", value);
+ return !(i%16);
}
static void pr_out_binary_value(struct dl *dl, uint8_t *data, uint32_t len)
{
- int i = 1;
-
- if (dl->json_output)
- jsonw_start_array(dl->jw);
- else
- pr_out("\n");
+ int i = 0;
while (i < len) {
- if (dl->json_output) {
- jsonw_printf(dl->jw, "%d", data[i]);
- } else {
- pr_out(" %02x", data[i]);
- if (!(i % 16))
- pr_out("\n");
- }
+ if (dl->json_output)
+ print_int(PRINT_JSON, NULL, NULL, data[i]);
+ else
+ pr_out("%02x ", data[i]);
i++;
+ if (!dl->json_output && is_binary_eol(i))
+ __pr_out_newline();
}
- if (dl->json_output)
- jsonw_end_array(dl->jw);
- else if ((i - 1) % 16)
- pr_out("\n");
-}
-
-static void pr_out_str_value(struct dl *dl, const char *value)
-{
- if (dl->json_output)
- jsonw_string(dl->jw, value);
- else
- pr_out(" %s", value);
+ if (!dl->json_output && !is_binary_eol(i))
+ __pr_out_newline();
}
static void pr_out_name(struct dl *dl, const char *name)
{
+ __pr_out_indent_newline(dl);
if (dl->json_output)
- jsonw_name(dl->jw, name);
+ print_string(PRINT_JSON, name, NULL, NULL);
else
- pr_out(" %s:", name);
+ pr_out("%s:", name);
}
static void pr_out_region_chunk_start(struct dl *dl, uint64_t addr)
{
if (dl->json_output) {
- jsonw_name(dl->jw, "address");
- jsonw_uint(dl->jw, addr);
- jsonw_name(dl->jw, "data");
- jsonw_start_array(dl->jw);
+ print_uint(PRINT_JSON, "address", NULL, addr);
+ open_json_array(PRINT_JSON, "data");
}
}
static void pr_out_region_chunk_end(struct dl *dl)
{
if (dl->json_output)
- jsonw_end_array(dl->jw);
+ close_json_array(PRINT_JSON, NULL);
}
static void pr_out_region_chunk(struct dl *dl, uint8_t *data, uint32_t len,
align_val++;
if (dl->json_output)
- jsonw_printf(dl->jw, "%d", data[i]);
+ print_int(PRINT_JSON, NULL, NULL, data[i]);
else
pr_out("%02x ", data[i]);
pr_out_region_chunk_end(dl);
}
-static void pr_out_dev(struct dl *dl, struct nlattr **tb)
-{
- pr_out_handle(dl, tb);
-}
-
static void pr_out_section_start(struct dl *dl, const char *name)
{
if (dl->json_output) {
- jsonw_start_object(dl->jw);
- jsonw_name(dl->jw, name);
- jsonw_start_object(dl->jw);
+ open_json_object(NULL);
+ open_json_object(name);
}
}
{
if (dl->json_output) {
if (dl->arr_last.present)
- jsonw_end_array(dl->jw);
- jsonw_end_object(dl->jw);
- jsonw_end_object(dl->jw);
+ close_json_array(PRINT_JSON, NULL);
+ close_json_object();
+ close_json_object();
}
}
static void pr_out_array_start(struct dl *dl, const char *name)
{
if (dl->json_output) {
- jsonw_name(dl->jw, name);
- jsonw_start_array(dl->jw);
+ open_json_array(PRINT_JSON, name);
} else {
__pr_out_indent_inc();
__pr_out_newline();
static void pr_out_array_end(struct dl *dl)
{
if (dl->json_output) {
- jsonw_end_array(dl->jw);
+ close_json_array(PRINT_JSON, NULL);
} else {
__pr_out_indent_dec();
__pr_out_indent_dec();
static void pr_out_object_start(struct dl *dl, const char *name)
{
if (dl->json_output) {
- jsonw_name(dl->jw, name);
- jsonw_start_object(dl->jw);
+ open_json_object(name);
} else {
__pr_out_indent_inc();
__pr_out_newline();
static void pr_out_object_end(struct dl *dl)
{
if (dl->json_output) {
- jsonw_end_object(dl->jw);
+ close_json_object();
} else {
__pr_out_indent_dec();
__pr_out_indent_dec();
static void pr_out_entry_start(struct dl *dl)
{
if (dl->json_output)
- jsonw_start_object(dl->jw);
+ open_json_object(NULL);
}
static void pr_out_entry_end(struct dl *dl)
{
if (dl->json_output)
- jsonw_end_object(dl->jw);
+ close_json_object();
else
__pr_out_newline();
}
+static void pr_out_stats(struct dl *dl, struct nlattr *nla_stats)
+{
+ struct nlattr *tb[DEVLINK_ATTR_STATS_MAX + 1] = {};
+ int err;
+
+ if (!dl->stats)
+ return;
+
+ err = mnl_attr_parse_nested(nla_stats, attr_stats_cb, tb);
+ if (err != MNL_CB_OK)
+ return;
+
+ pr_out_object_start(dl, "stats");
+ pr_out_object_start(dl, "rx");
+ if (tb[DEVLINK_ATTR_STATS_RX_BYTES])
+ pr_out_u64(dl, "bytes",
+ mnl_attr_get_u64(tb[DEVLINK_ATTR_STATS_RX_BYTES]));
+ if (tb[DEVLINK_ATTR_STATS_RX_PACKETS])
+ pr_out_u64(dl, "packets",
+ mnl_attr_get_u64(tb[DEVLINK_ATTR_STATS_RX_PACKETS]));
+ pr_out_object_end(dl);
+ pr_out_object_end(dl);
+}
+
static const char *param_cmode_name(uint8_t cmode)
{
switch (cmode) {
{
__pr_out_handle_start(dl, tb, true, false);
- if (tb[DEVLINK_ATTR_ESWITCH_MODE])
- pr_out_str(dl, "mode",
- eswitch_mode_name(mnl_attr_get_u16(tb[DEVLINK_ATTR_ESWITCH_MODE])));
-
- if (tb[DEVLINK_ATTR_ESWITCH_INLINE_MODE])
- pr_out_str(dl, "inline-mode",
- eswitch_inline_mode_name(mnl_attr_get_u8(
- tb[DEVLINK_ATTR_ESWITCH_INLINE_MODE])));
-
+ if (tb[DEVLINK_ATTR_ESWITCH_MODE]) {
+ check_indent_newline(dl);
+ print_string(PRINT_ANY, "mode", "mode %s",
+ eswitch_mode_name(mnl_attr_get_u16(
+ tb[DEVLINK_ATTR_ESWITCH_MODE])));
+ }
+ if (tb[DEVLINK_ATTR_ESWITCH_INLINE_MODE]) {
+ check_indent_newline(dl);
+ print_string(PRINT_ANY, "inline-mode", "inline-mode %s",
+ eswitch_inline_mode_name(mnl_attr_get_u8(
+ tb[DEVLINK_ATTR_ESWITCH_INLINE_MODE])));
+ }
if (tb[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]) {
bool encap_mode = !!mnl_attr_get_u8(tb[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]);
- pr_out_str(dl, "encap", encap_mode ? "enable" : "disable");
+ check_indent_newline(dl);
+ print_string(PRINT_ANY, "encap", "encap %s",
+ encap_mode ? "enable" : "disable");
}
pr_out_handle_end(dl);
.vstr = "flash",
.vuint = DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH,
},
+ {
+ .name = "reset_dev_on_drv_probe",
+ .vstr = "unknown",
+ .vuint = DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_UNKNOWN,
+ },
+ {
+ .name = "fw_load_policy",
+ .vstr = "unknown",
+ .vuint = DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_UNKNOWN,
+ },
+ {
+ .name = "reset_dev_on_drv_probe",
+ .vstr = "always",
+ .vuint = DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_ALWAYS,
+ },
+ {
+ .name = "reset_dev_on_drv_probe",
+ .vstr = "never",
+ .vuint = DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_NEVER,
+ },
+ {
+ .name = "reset_dev_on_drv_probe",
+ .vstr = "disk",
+ .vuint = DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_DISK,
+ },
};
#define PARAM_VAL_CONV_LEN ARRAY_SIZE(param_val_conv)
!nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA]))
return;
- pr_out_str(dl, "cmode",
- param_cmode_name(mnl_attr_get_u8(nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE])));
+ check_indent_newline(dl);
+ print_string(PRINT_ANY, "cmode", "cmode %s",
+ param_cmode_name(mnl_attr_get_u8(nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE])));
+
val_attr = nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA];
conv_exists = param_val_conv_exists(param_val_conv, PARAM_VAL_CONV_LEN,
&vstr);
if (err)
return;
- pr_out_str(dl, "value", vstr);
+ print_string(PRINT_ANY, "value", " value %s", vstr);
} else {
pr_out_uint(dl, "value", mnl_attr_get_u8(val_attr));
}
&vstr);
if (err)
return;
- pr_out_str(dl, "value", vstr);
+ print_string(PRINT_ANY, "value", " value %s", vstr);
} else {
pr_out_uint(dl, "value", mnl_attr_get_u16(val_attr));
}
&vstr);
if (err)
return;
- pr_out_str(dl, "value", vstr);
+ print_string(PRINT_ANY, "value", " value %s", vstr);
} else {
pr_out_uint(dl, "value", mnl_attr_get_u32(val_attr));
}
break;
case MNL_TYPE_STRING:
- pr_out_str(dl, "value", mnl_attr_get_str(val_attr));
+ print_string(PRINT_ANY, "value", " value %s",
+ mnl_attr_get_str(val_attr));
break;
case MNL_TYPE_FLAG:
pr_out_bool(dl, "value", val_attr ? true : false);
nla_type = mnl_attr_get_u8(nla_param[DEVLINK_ATTR_PARAM_TYPE]);
nla_name = mnl_attr_get_str(nla_param[DEVLINK_ATTR_PARAM_NAME]);
- pr_out_str(dl, "name", nla_name);
-
+ check_indent_newline(dl);
+ print_string(PRINT_ANY, "name", "name %s ", nla_name);
if (!nla_param[DEVLINK_ATTR_PARAM_GENERIC])
- pr_out_str(dl, "type", "driver-specific");
+ print_string(PRINT_ANY, "type", "type %s", "driver-specific");
else
- pr_out_str(dl, "type", "generic");
+ print_string(PRINT_ANY, "type", "type %s", "generic");
pr_out_array_start(dl, "values");
mnl_attr_for_each_nested(param_value_attr,
struct dl *dl = data;
struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
+ uint8_t reload_failed = 0;
mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
return MNL_CB_ERROR;
- pr_out_dev(dl, tb);
+
+ if (tb[DEVLINK_ATTR_RELOAD_FAILED])
+ reload_failed = mnl_attr_get_u8(tb[DEVLINK_ATTR_RELOAD_FAILED]);
+
+ if (reload_failed) {
+ __pr_out_handle_start(dl, tb, true, false);
+ pr_out_bool(dl, "reload_failed", true);
+ pr_out_handle_end(dl);
+ } else {
+ pr_out_handle(dl, tb);
+ }
+
return MNL_CB_OK;
}
static void cmd_dev_reload_help(void)
{
- pr_err("Usage: devlink dev reload [ DEV ]\n");
+ pr_err("Usage: devlink dev reload DEV [ netns { PID | NAME | ID } ]\n");
}
static int cmd_dev_reload(struct dl *dl)
nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RELOAD,
NLM_F_REQUEST | NLM_F_ACK);
- err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
+ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_NETNS);
if (err)
return err;
ver_name = mnl_attr_get_str(tb[DEVLINK_ATTR_INFO_VERSION_NAME]);
ver_value = mnl_attr_get_str(tb[DEVLINK_ATTR_INFO_VERSION_VALUE]);
- pr_out_str(dl, ver_name, ver_value);
+ check_indent_newline(dl);
+ print_string_name_value(ver_name, ver_value);
if (!dl->json_output)
__pr_out_newline();
}
if (!dl->json_output)
__pr_out_newline();
- pr_out_str(dl, "driver", mnl_attr_get_str(nla_drv));
+ check_indent_newline(dl);
+ print_string(PRINT_ANY, "driver", "driver %s",
+ mnl_attr_get_str(nla_drv));
}
if (tb[DEVLINK_ATTR_INFO_SERIAL_NUMBER]) {
if (!dl->json_output)
__pr_out_newline();
- pr_out_str(dl, "serial_number", mnl_attr_get_str(nla_sn));
+ check_indent_newline(dl);
+ print_string(PRINT_ANY, "serial_number", "serial_number %s",
+ mnl_attr_get_str(nla_sn));
}
__pr_out_indent_dec();
pr_err("Usage: devlink dev flash DEV file PATH [ component NAME ]\n");
}
+
+struct cmd_dev_flash_status_ctx {
+ struct dl *dl;
+ char *last_msg;
+ char *last_component;
+ uint8_t not_first:1,
+ last_pc:1,
+ received_end:1,
+ flash_done:1;
+};
+
+static int nullstrcmp(const char *str1, const char *str2)
+{
+ if (str1 && str2)
+ return strcmp(str1, str2);
+ if (!str1 && !str2)
+ return 0;
+ return str1 ? 1 : -1;
+}
+
+static int cmd_dev_flash_status_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct cmd_dev_flash_status_ctx *ctx = data;
+ struct dl_opts *opts = &ctx->dl->opts;
+ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
+ struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
+ const char *component = NULL;
+ uint64_t done = 0, total = 0;
+ const char *msg = NULL;
+ const char *bus_name;
+ const char *dev_name;
+
+ if (genl->cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS &&
+ genl->cmd != DEVLINK_CMD_FLASH_UPDATE_END)
+ return MNL_CB_STOP;
+
+ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
+ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
+ return MNL_CB_ERROR;
+ bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
+ dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
+ if (strcmp(bus_name, opts->bus_name) ||
+ strcmp(dev_name, opts->dev_name))
+ return MNL_CB_ERROR;
+
+ if (genl->cmd == DEVLINK_CMD_FLASH_UPDATE_END && ctx->not_first) {
+ pr_out("\n");
+ free(ctx->last_msg);
+ free(ctx->last_component);
+ ctx->received_end = 1;
+ return MNL_CB_STOP;
+ }
+
+ if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG])
+ msg = mnl_attr_get_str(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG]);
+ if (tb[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT])
+ component = mnl_attr_get_str(tb[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT]);
+ if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE])
+ done = mnl_attr_get_u64(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE]);
+ if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL])
+ total = mnl_attr_get_u64(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL]);
+
+ if (!nullstrcmp(msg, ctx->last_msg) &&
+ !nullstrcmp(component, ctx->last_component) &&
+ ctx->last_pc && ctx->not_first) {
+ pr_out_tty("\b\b\b\b\b"); /* clean percentage */
+ } else {
+ if (ctx->not_first)
+ pr_out("\n");
+ if (component) {
+ pr_out("[%s] ", component);
+ free(ctx->last_component);
+ ctx->last_component = strdup(component);
+ }
+ if (msg) {
+ pr_out("%s", msg);
+ free(ctx->last_msg);
+ ctx->last_msg = strdup(msg);
+ }
+ }
+ if (total) {
+ pr_out_tty(" %3lu%%", (done * 100) / total);
+ ctx->last_pc = 1;
+ } else {
+ ctx->last_pc = 0;
+ }
+ fflush(stdout);
+ ctx->not_first = 1;
+
+ return MNL_CB_STOP;
+}
+
+static int cmd_dev_flash_fds_process(struct cmd_dev_flash_status_ctx *ctx,
+ struct mnlg_socket *nlg_ntf,
+ int pipe_r)
+{
+ int nlfd = mnlg_socket_get_fd(nlg_ntf);
+ fd_set fds[3];
+ int fdmax;
+ int i;
+ int err;
+ int err2;
+
+ for (i = 0; i < 3; i++)
+ FD_ZERO(&fds[i]);
+ FD_SET(pipe_r, &fds[0]);
+ fdmax = pipe_r + 1;
+ FD_SET(nlfd, &fds[0]);
+ if (nlfd >= fdmax)
+ fdmax = nlfd + 1;
+
+ while (select(fdmax, &fds[0], &fds[1], &fds[2], NULL) < 0) {
+ if (errno == EINTR)
+ continue;
+ pr_err("select() failed\n");
+ return -errno;
+ }
+ if (FD_ISSET(nlfd, &fds[0])) {
+ err = _mnlg_socket_recv_run(nlg_ntf,
+ cmd_dev_flash_status_cb, ctx);
+ if (err)
+ return err;
+ }
+ if (FD_ISSET(pipe_r, &fds[0])) {
+ err = read(pipe_r, &err2, sizeof(err2));
+ if (err == -1) {
+ pr_err("Failed to read pipe\n");
+ return -errno;
+ }
+ if (err2)
+ return err2;
+ ctx->flash_done = 1;
+ }
+ return 0;
+}
+
+
static int cmd_dev_flash(struct dl *dl)
{
+ struct cmd_dev_flash_status_ctx ctx = {.dl = dl,};
+ struct mnlg_socket *nlg_ntf;
struct nlmsghdr *nlh;
+ int pipe_r, pipe_w;
+ int pipe_fds[2];
+ pid_t pid;
int err;
if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
if (err)
return err;
- return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
+ nlg_ntf = mnlg_socket_open(DEVLINK_GENL_NAME, DEVLINK_GENL_VERSION);
+ if (!nlg_ntf)
+ return err;
+
+ err = _mnlg_socket_group_add(nlg_ntf, DEVLINK_GENL_MCGRP_CONFIG_NAME);
+ if (err)
+ return err;
+
+ err = pipe(pipe_fds);
+ if (err == -1)
+ return -errno;
+ pipe_r = pipe_fds[0];
+ pipe_w = pipe_fds[1];
+
+ pid = fork();
+ if (pid == -1) {
+ close(pipe_r);
+ close(pipe_w);
+ return -errno;
+ } else if (!pid) {
+ /* In child, just execute the flash and pass returned
+ * value through pipe once it is done.
+ */
+ close(pipe_r);
+ err = _mnlg_socket_send(dl->nlg, nlh);
+ write(pipe_w, &err, sizeof(err));
+ close(pipe_w);
+ exit(0);
+ }
+ close(pipe_w);
+
+ do {
+ err = cmd_dev_flash_fds_process(&ctx, nlg_ntf, pipe_r);
+ if (err)
+ goto out;
+ } while (!ctx.flash_done || (ctx.not_first && !ctx.received_end));
+
+ err = _mnlg_socket_recv_run(dl->nlg, NULL, NULL);
+out:
+ close(pipe_r);
+ mnlg_socket_close(nlg_ntf);
+ return err;
}
static int cmd_dev(struct dl *dl)
return "cpu";
case DEVLINK_PORT_FLAVOUR_DSA:
return "dsa";
+ case DEVLINK_PORT_FLAVOUR_PCI_PF:
+ return "pcipf";
+ case DEVLINK_PORT_FLAVOUR_PCI_VF:
+ return "pcivf";
default:
return "<unknown flavour>";
}
}
+static void pr_out_port_pfvf_num(struct dl *dl, struct nlattr **tb)
+{
+ uint16_t fn_num;
+
+ if (tb[DEVLINK_ATTR_PORT_PCI_PF_NUMBER]) {
+ fn_num = mnl_attr_get_u16(tb[DEVLINK_ATTR_PORT_PCI_PF_NUMBER]);
+ pr_out_uint(dl, "pfnum", fn_num);
+ }
+ if (tb[DEVLINK_ATTR_PORT_PCI_VF_NUMBER]) {
+ fn_num = mnl_attr_get_u16(tb[DEVLINK_ATTR_PORT_PCI_VF_NUMBER]);
+ pr_out_uint(dl, "vfnum", fn_num);
+ }
+}
+
static void pr_out_port(struct dl *dl, struct nlattr **tb)
{
struct nlattr *pt_attr = tb[DEVLINK_ATTR_PORT_TYPE];
struct nlattr *dpt_attr = tb[DEVLINK_ATTR_PORT_DESIRED_TYPE];
pr_out_port_handle_start(dl, tb, false);
+ check_indent_newline(dl);
if (pt_attr) {
uint16_t port_type = mnl_attr_get_u16(pt_attr);
- pr_out_str(dl, "type", port_type_name(port_type));
+ print_string(PRINT_ANY, "type", "type %s",
+ port_type_name(port_type));
if (dpt_attr) {
uint16_t des_port_type = mnl_attr_get_u16(dpt_attr);
if (port_type != des_port_type)
- pr_out_str(dl, "des_type",
- port_type_name(des_port_type));
+ print_string(PRINT_ANY, "des_type", " des_type %s",
+ port_type_name(des_port_type));
}
}
- if (tb[DEVLINK_ATTR_PORT_NETDEV_NAME])
- pr_out_str(dl, "netdev",
- mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME]));
- if (tb[DEVLINK_ATTR_PORT_IBDEV_NAME])
- pr_out_str(dl, "ibdev",
- mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_IBDEV_NAME]));
+ if (tb[DEVLINK_ATTR_PORT_NETDEV_NAME]) {
+ print_string(PRINT_ANY, "netdev", " netdev %s",
+ mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME]));
+ }
+ if (tb[DEVLINK_ATTR_PORT_IBDEV_NAME]) {
+ print_string(PRINT_ANY, "ibdev", " ibdev %s",
+ mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_IBDEV_NAME]));
+ }
if (tb[DEVLINK_ATTR_PORT_FLAVOUR]) {
uint16_t port_flavour =
mnl_attr_get_u16(tb[DEVLINK_ATTR_PORT_FLAVOUR]);
- pr_out_str(dl, "flavour", port_flavour_name(port_flavour));
+ print_string(PRINT_ANY, "flavour", " flavour %s",
+ port_flavour_name(port_flavour));
+
+ switch (port_flavour) {
+ case DEVLINK_PORT_FLAVOUR_PCI_PF:
+ case DEVLINK_PORT_FLAVOUR_PCI_VF:
+ pr_out_port_pfvf_num(dl, tb);
+ break;
+ default:
+ break;
+ }
+ }
+ if (tb[DEVLINK_ATTR_PORT_NUMBER]) {
+ uint32_t port_number;
+
+ port_number = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_NUMBER]);
+ pr_out_uint(dl, "port", port_number);
}
if (tb[DEVLINK_ATTR_PORT_SPLIT_GROUP])
pr_out_uint(dl, "split_group",
static void pr_out_sb(struct dl *dl, struct nlattr **tb)
{
pr_out_handle_start_arr(dl, tb);
+ check_indent_newline(dl);
pr_out_uint(dl, "sb",
mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
pr_out_uint(dl, "size",
mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
pr_out_uint(dl, "pool",
mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]));
- pr_out_str(dl, "type",
- pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])));
+ print_string(PRINT_ANY, "type", " type %s",
+ pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])));
pr_out_uint(dl, "size",
mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_SIZE]));
- pr_out_str(dl, "thtype",
- threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])));
+ print_string(PRINT_ANY, "thtype", " thtype %s",
+ threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])));
if (tb[DEVLINK_ATTR_SB_POOL_CELL_SIZE])
pr_out_uint(dl, "cell_size",
mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_CELL_SIZE]));
mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
pr_out_uint(dl, "tc",
mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]));
- pr_out_str(dl, "type",
- pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])));
+ print_string(PRINT_ANY, "type", " type %s",
+ pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])));
pr_out_uint(dl, "pool",
mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]));
pr_out_uint(dl, "threshold",
struct occ_item *occ_item;
char buf[32];
- jsonw_name(dl->jw, label);
- jsonw_start_object(dl->jw);
+ open_json_object(label);
list_for_each_entry(occ_item, list, list) {
sprintf(buf, "%u", occ_item->index);
- jsonw_name(dl->jw, buf);
- jsonw_start_object(dl->jw);
+ open_json_object(buf);
if (bound_pool)
- jsonw_uint_field(dl->jw, "bound_pool",
- occ_item->bound_pool_index);
- jsonw_uint_field(dl->jw, "current", occ_item->cur);
- jsonw_uint_field(dl->jw, "max", occ_item->max);
- jsonw_end_object(dl->jw);
+ print_uint(PRINT_JSON, "bound_pool", NULL,
+ occ_item->bound_pool_index);
+ print_uint(PRINT_JSON, "current", NULL, occ_item->cur);
+ print_uint(PRINT_JSON, "max", NULL, occ_item->max);
+ close_json_object();
}
- jsonw_end_object(dl->jw);
+ close_json_object();
}
static void pr_out_occ_show_port(struct dl *dl, struct occ_port *occ_port)
case DEVLINK_CMD_REGION_SET: return "set";
case DEVLINK_CMD_REGION_NEW: return "new";
case DEVLINK_CMD_REGION_DEL: return "del";
+ case DEVLINK_CMD_FLASH_UPDATE: return "begin";
+ case DEVLINK_CMD_FLASH_UPDATE_END: return "end";
+ case DEVLINK_CMD_FLASH_UPDATE_STATUS: return "status";
+ case DEVLINK_CMD_TRAP_GET: return "get";
+ case DEVLINK_CMD_TRAP_SET: return "set";
+ case DEVLINK_CMD_TRAP_NEW: return "new";
+ case DEVLINK_CMD_TRAP_DEL: return "del";
+ case DEVLINK_CMD_TRAP_GROUP_GET: return "get";
+ case DEVLINK_CMD_TRAP_GROUP_SET: return "set";
+ case DEVLINK_CMD_TRAP_GROUP_NEW: return "new";
+ case DEVLINK_CMD_TRAP_GROUP_DEL: return "del";
default: return "<unknown cmd>";
}
}
case DEVLINK_CMD_REGION_NEW:
case DEVLINK_CMD_REGION_DEL:
return "region";
+ case DEVLINK_CMD_FLASH_UPDATE:
+ case DEVLINK_CMD_FLASH_UPDATE_END:
+ case DEVLINK_CMD_FLASH_UPDATE_STATUS:
+ return "flash";
+ case DEVLINK_CMD_TRAP_GET:
+ case DEVLINK_CMD_TRAP_SET:
+ case DEVLINK_CMD_TRAP_NEW:
+ case DEVLINK_CMD_TRAP_DEL:
+ return "trap";
+ case DEVLINK_CMD_TRAP_GROUP_GET:
+ case DEVLINK_CMD_TRAP_GROUP_SET:
+ case DEVLINK_CMD_TRAP_GROUP_NEW:
+ case DEVLINK_CMD_TRAP_GROUP_DEL:
+ return "trap-group";
default: return "<unknown obj>";
}
}
return false;
}
+static void pr_out_flash_update(struct dl *dl, struct nlattr **tb)
+{
+ __pr_out_handle_start(dl, tb, true, false);
+
+ if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG]) {
+ check_indent_newline(dl);
+ print_string(PRINT_ANY, "msg", "msg %s",
+ mnl_attr_get_str(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG]));
+ }
+ if (tb[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT]) {
+ check_indent_newline(dl);
+ print_string(PRINT_ANY, "component", "component %s",
+ mnl_attr_get_str(tb[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT]));
+ }
+
+ if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE])
+ pr_out_u64(dl, "done",
+ mnl_attr_get_u64(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE]));
+
+ if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL])
+ pr_out_u64(dl, "total",
+ mnl_attr_get_u64(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL]));
+
+ pr_out_handle_end(dl);
+}
+
static void pr_out_region(struct dl *dl, struct nlattr **tb);
+static void pr_out_trap(struct dl *dl, struct nlattr **tb, bool array);
+static void pr_out_trap_group(struct dl *dl, struct nlattr **tb, bool array);
static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data)
{
if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
return MNL_CB_ERROR;
pr_out_mon_header(genl->cmd);
- pr_out_dev(dl, tb);
+ pr_out_handle(dl, tb);
break;
case DEVLINK_CMD_PORT_GET: /* fall through */
case DEVLINK_CMD_PORT_SET: /* fall through */
pr_out_mon_header(genl->cmd);
pr_out_region(dl, tb);
break;
- }
+ case DEVLINK_CMD_FLASH_UPDATE: /* fall through */
+ case DEVLINK_CMD_FLASH_UPDATE_END: /* fall through */
+ case DEVLINK_CMD_FLASH_UPDATE_STATUS:
+ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
+ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
+ return MNL_CB_ERROR;
+ pr_out_mon_header(genl->cmd);
+ pr_out_flash_update(dl, tb);
+ break;
+ case DEVLINK_CMD_TRAP_GET: /* fall through */
+ case DEVLINK_CMD_TRAP_SET: /* fall through */
+ case DEVLINK_CMD_TRAP_NEW: /* fall through */
+ case DEVLINK_CMD_TRAP_DEL:
+ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
+ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
+ !tb[DEVLINK_ATTR_TRAP_NAME] ||
+ !tb[DEVLINK_ATTR_TRAP_TYPE] ||
+ !tb[DEVLINK_ATTR_TRAP_ACTION] ||
+ !tb[DEVLINK_ATTR_TRAP_GROUP_NAME] ||
+ !tb[DEVLINK_ATTR_TRAP_METADATA] ||
+ !tb[DEVLINK_ATTR_STATS])
+ return MNL_CB_ERROR;
+ pr_out_mon_header(genl->cmd);
+ pr_out_trap(dl, tb, false);
+ break;
+ case DEVLINK_CMD_TRAP_GROUP_GET: /* fall through */
+ case DEVLINK_CMD_TRAP_GROUP_SET: /* fall through */
+ case DEVLINK_CMD_TRAP_GROUP_NEW: /* fall through */
+ case DEVLINK_CMD_TRAP_GROUP_DEL:
+ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
+ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
+ !tb[DEVLINK_ATTR_TRAP_GROUP_NAME] ||
+ !tb[DEVLINK_ATTR_STATS])
+ return MNL_CB_ERROR;
+ pr_out_mon_header(genl->cmd);
+ pr_out_trap_group(dl, tb, false);
+ break;
+ }
return MNL_CB_OK;
}
while ((cur_obj = dl_argv_index(dl, index++))) {
if (strcmp(cur_obj, "all") != 0 &&
strcmp(cur_obj, "dev") != 0 &&
- strcmp(cur_obj, "port") != 0) {
+ strcmp(cur_obj, "port") != 0 &&
+ strcmp(cur_obj, "trap") != 0 &&
+ strcmp(cur_obj, "trap-group") != 0) {
pr_err("Unknown object \"%s\"\n", cur_obj);
return -EINVAL;
}
static void cmd_mon_help(void)
{
pr_err("Usage: devlink monitor [ all | OBJECT-LIST ]\n"
- "where OBJECT-LIST := { dev | port }\n");
+ "where OBJECT-LIST := { dev | port | trap | trap-group }\n");
}
static int cmd_mon(struct dl *dl)
for (i = 0; i < field_count; i++) {
field = &fields[i];
pr_out_entry_start(ctx->dl);
- pr_out_str(ctx->dl, "name", field->name);
+ check_indent_newline(ctx->dl);
+ print_string(PRINT_ANY, "name", "name %s", field->name);
if (ctx->dl->verbose)
pr_out_uint(ctx->dl, "id", field->id);
pr_out_uint(ctx->dl, "bitwidth", field->bitwidth);
- if (field->mapping_type)
- pr_out_str(ctx->dl, "mapping_type",
- dpipe_field_mapping_e2s(field->mapping_type));
+ if (field->mapping_type) {
+ print_string(PRINT_ANY, "mapping_type", " mapping_type %s",
+ dpipe_field_mapping_e2s(field->mapping_type));
+ }
pr_out_entry_end(ctx->dl);
}
}
struct dpipe_header *header, bool global)
{
pr_out_handle_start_arr(ctx->dl, tb);
- pr_out_str(ctx->dl, "name", header->name);
+ check_indent_newline(ctx->dl);
+ print_string(PRINT_ANY, "name", "name %s", header->name);
if (ctx->dl->verbose) {
pr_out_uint(ctx->dl, "id", header->id);
- pr_out_str(ctx->dl, "global",
- global ? "true" : "false");
+ print_bool(PRINT_ANY, "global", " global %s", global);
}
pr_out_array_start(ctx->dl, "field");
pr_out_dpipe_fields(ctx, header->fields,
struct dpipe_op_info *op_info = &action->info;
const char *mapping;
- pr_out_str(ctx->dl, "type",
- dpipe_action_type_e2s(action->type));
- pr_out_str(ctx->dl, "header",
- dpipe_header_id2s(ctx, op_info->header_id,
- op_info->header_global));
- pr_out_str(ctx->dl, "field",
- dpipe_field_id2s(ctx, op_info->header_id,
- op_info->field_id,
- op_info->header_global));
+ check_indent_newline(ctx->dl);
+ print_string(PRINT_ANY, "type", "type %s",
+ dpipe_action_type_e2s(action->type));
+ print_string(PRINT_ANY, "header", " header %s",
+ dpipe_header_id2s(ctx, op_info->header_id,
+ op_info->header_global));
+ print_string(PRINT_ANY, "field", " field %s",
+ dpipe_field_id2s(ctx, op_info->header_id,
+ op_info->field_id,
+ op_info->header_global));
mapping = dpipe_mapping_get(ctx, op_info->header_id,
op_info->field_id,
op_info->header_global);
if (mapping)
- pr_out_str(ctx->dl, "mapping", mapping);
+ print_string(PRINT_ANY, "mapping", " mapping %s", mapping);
}
static int dpipe_action_parse(struct dpipe_action *action, struct nlattr *nl)
struct dpipe_op_info *op_info = &match->info;
const char *mapping;
- pr_out_str(ctx->dl, "type",
- dpipe_match_type_e2s(match->type));
- pr_out_str(ctx->dl, "header",
- dpipe_header_id2s(ctx, op_info->header_id,
- op_info->header_global));
- pr_out_str(ctx->dl, "field",
- dpipe_field_id2s(ctx, op_info->header_id,
- op_info->field_id,
- op_info->header_global));
+ check_indent_newline(ctx->dl);
+ print_string(PRINT_ANY, "type", "type %s",
+ dpipe_match_type_e2s(match->type));
+ print_string(PRINT_ANY, "header", " header %s",
+ dpipe_header_id2s(ctx, op_info->header_id,
+ op_info->header_global));
+ print_string(PRINT_ANY, "field", " field %s",
+ dpipe_field_id2s(ctx, op_info->header_id,
+ op_info->field_id,
+ op_info->header_global));
mapping = dpipe_mapping_get(ctx, op_info->header_id,
op_info->field_id,
op_info->header_global);
if (mapping)
- pr_out_str(ctx->dl, "mapping", mapping);
+ print_string(PRINT_ANY, "mapping", " mapping %s", mapping);
}
static int dpipe_match_parse(struct dpipe_match *match,
path -= strlen(del);
memcpy(path, del, strlen(del));
}
- pr_out_str(dl, "resource_path", path);
+ check_indent_newline(dl);
+ print_string(PRINT_ANY, "resource_path", "resource_path %s", path);
free(path);
}
if (!ctx->print_tables)
return 0;
- pr_out_str(ctx->dl, "name", table->name);
+ check_indent_newline(ctx->dl);
+ print_string(PRINT_ANY, "name", "name %s", table->name);
pr_out_uint(ctx->dl, "size", size);
- pr_out_str(ctx->dl, "counters_enabled",
- counters_enabled ? "true" : "false");
+ print_bool(PRINT_ANY, "counters_enabled", " counters_enabled %s", counters_enabled);
if (resource_valid) {
resource_units = mnl_attr_get_u32(nla_table[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS]);
struct in_addr ip_addr;
ip_addr.s_addr = htonl(*(uint32_t *)value);
- pr_out_str(ctx->dl, dpipe_value_type_e2s(type), inet_ntoa(ip_addr));
+ check_indent_newline(ctx->dl);
+ print_string_name_value(dpipe_value_type_e2s(type), inet_ntoa(ip_addr));
}
static void
enum dpipe_value_type type,
void *value)
{
- pr_out_str(ctx->dl, dpipe_value_type_e2s(type),
- ether_ntoa((struct ether_addr *)value));
+ check_indent_newline(ctx->dl);
+ print_string_name_value(dpipe_value_type_e2s(type),
+ ether_ntoa((struct ether_addr *)value));
}
static void dpipe_field_printer_ipv6_addr(struct dpipe_ctx *ctx,
char str[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, value, str, INET6_ADDRSTRLEN);
- pr_out_str(ctx->dl, dpipe_value_type_e2s(type), str);
+ check_indent_newline(ctx->dl);
+ print_string_name_value(dpipe_value_type_e2s(type), str);
}
static struct dpipe_field_printer dpipe_field_printers_ipv4[] = {
struct dl *dl = ctx->dl;
bool array = false;
- pr_out_str(dl, "name", resource->name);
+ check_indent_newline(dl);
+ print_string(PRINT_ANY, "name", "name %s", resource->name);
if (dl->verbose)
resource_path_print(dl, ctx->resources, resource->id);
pr_out_u64(dl, "size", resource->size);
pr_out_u64(dl, "size_new", resource->size_new);
if (resource->occ_valid)
pr_out_uint(dl, "occ", resource->size_occ);
- pr_out_str(dl, "unit", resource_unit_str_get(resource->unit));
+ print_string(PRINT_ANY, "unit", " unit %s",
+ resource_unit_str_get(resource->unit));
if (resource->size_min != resource->size_max) {
pr_out_uint(dl, "size_min", resource->size_min);
if (array)
pr_out_array_start(dl, "dpipe_tables");
else
- pr_out_str(dl, "dpipe_tables", "none");
+ print_string(PRINT_ANY, "dpipe_tables", " dpipe_tables none",
+ "none");
list_for_each_entry(table, &ctx->tables->table_list, list) {
if (table->resource_id != resource->id ||
!table->resource_valid)
continue;
pr_out_entry_start(dl);
- pr_out_str(dl, "table_name", table->name);
+ check_indent_newline(dl);
+ print_string(PRINT_ANY, "table_name", "table_name %s",
+ table->name);
pr_out_entry_end(dl);
}
if (array)
if (list_empty(&resource->resource_list))
return;
- if (ctx->pending_change)
- pr_out_str(dl, "size_valid", resource->size_valid ?
- "true" : "false");
+ if (ctx->pending_change) {
+ check_indent_newline(dl);
+ print_string(PRINT_ANY, "size_valid", "size_valid %s",
+ resource->size_valid ? "true" : "false");
+ }
pr_out_array_start(dl, "resources");
list_for_each_entry(child_resource, &resource->resource_list, list) {
pr_out_entry_start(dl);
char buf[256];
sprintf(buf, "%s/%s/%s", bus_name, dev_name, region_name);
- if (dl->json_output) {
- jsonw_name(dl->jw, buf);
- jsonw_start_object(dl->jw);
- } else {
+ if (dl->json_output)
+ open_json_object(buf);
+ else
pr_out("%s:", buf);
- }
}
static void pr_out_region_handle_end(struct dl *dl)
{
if (dl->json_output)
- jsonw_end_object(dl->jw);
+ close_json_object();
else
pr_out("\n");
}
static void pr_out_region_snapshots_start(struct dl *dl, bool array)
{
- if (dl->json_output) {
- jsonw_name(dl->jw, "snapshot");
- jsonw_start_array(dl->jw);
- } else {
- if (g_indent_newline)
- pr_out("snapshot %s", array ? "[" : "");
- else
- pr_out(" snapshot %s", array ? "[" : "");
- }
+ __pr_out_indent_newline(dl);
+ if (dl->json_output)
+ open_json_array(PRINT_JSON, "snapshot");
+ else
+ pr_out("snapshot %s", array ? "[" : "");
}
static void pr_out_region_snapshots_end(struct dl *dl, bool array)
{
if (dl->json_output)
- jsonw_end_array(dl->jw);
+ close_json_array(PRINT_JSON, NULL);
else if (array)
pr_out("]");
}
snapshot_id = mnl_attr_get_u32(tb[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
if (dl->json_output)
- jsonw_uint(dl->jw, snapshot_id);
+ print_uint(PRINT_JSON, NULL, NULL, snapshot_id);
else
pr_out("%s%u", index ? " " : "", snapshot_id);
}
uint8_t *data;
uint32_t len;
+ check_indent_newline(dl);
switch (type) {
case MNL_TYPE_FLAG:
- pr_out_bool_value(dl, mnl_attr_get_u8(nl_data));
+ print_bool(PRINT_ANY, NULL, "%s", mnl_attr_get_u8(nl_data));
break;
case MNL_TYPE_U8:
- pr_out_uint_value(dl, mnl_attr_get_u8(nl_data));
+ print_uint(PRINT_ANY, NULL, "%u", mnl_attr_get_u8(nl_data));
break;
case MNL_TYPE_U16:
- pr_out_uint_value(dl, mnl_attr_get_u16(nl_data));
+ print_uint(PRINT_ANY, NULL, "%u", mnl_attr_get_u16(nl_data));
break;
case MNL_TYPE_U32:
- pr_out_uint_value(dl, mnl_attr_get_u32(nl_data));
+ print_uint(PRINT_ANY, NULL, "%u", mnl_attr_get_u32(nl_data));
break;
case MNL_TYPE_U64:
- pr_out_uint64_value(dl, mnl_attr_get_u64(nl_data));
+ print_u64(PRINT_ANY, NULL, "%"PRIu64, mnl_attr_get_u64(nl_data));
break;
case MNL_TYPE_NUL_STRING:
- pr_out_str_value(dl, mnl_attr_get_str(nl_data));
+ print_string(PRINT_ANY, NULL, "%s", mnl_attr_get_str(nl_data));
break;
case MNL_TYPE_BINARY:
len = mnl_attr_get_payload_len(nl_data);
return MNL_CB_OK;
}
-struct nest_qentry {
+static void pr_out_fmsg_name(struct dl *dl, char **name)
+{
+ if (!*name)
+ return;
+
+ pr_out_name(dl, *name);
+ free(*name);
+ *name = NULL;
+}
+
+struct nest_entry {
int attr_type;
- TAILQ_ENTRY(nest_qentry) nest_entries;
+ struct list_head list;
};
struct fmsg_cb_data {
+ char *name;
struct dl *dl;
uint8_t value_type;
- TAILQ_HEAD(, nest_qentry) qhead;
+ struct list_head entry_list;
};
static int cmd_fmsg_nest_queue(struct fmsg_cb_data *fmsg_data,
uint8_t *attr_value, bool insert)
{
- struct nest_qentry *entry = NULL;
+ struct nest_entry *entry;
if (insert) {
- entry = malloc(sizeof(struct nest_qentry));
+ entry = malloc(sizeof(struct nest_entry));
if (!entry)
return -ENOMEM;
entry->attr_type = *attr_value;
- TAILQ_INSERT_HEAD(&fmsg_data->qhead, entry, nest_entries);
+ list_add(&entry->list, &fmsg_data->entry_list);
} else {
- if (TAILQ_EMPTY(&fmsg_data->qhead))
+ if (list_empty(&fmsg_data->entry_list))
return MNL_CB_ERROR;
- entry = TAILQ_FIRST(&fmsg_data->qhead);
+ entry = list_first_entry(&fmsg_data->entry_list,
+ struct nest_entry, list);
*attr_value = entry->attr_type;
- TAILQ_REMOVE(&fmsg_data->qhead, entry, nest_entries);
+ list_del(&entry->list);
free(entry);
}
return MNL_CB_OK;
}
+static void pr_out_fmsg_group_start(struct dl *dl, char **name)
+{
+ __pr_out_newline();
+ pr_out_fmsg_name(dl, name);
+ __pr_out_newline();
+ __pr_out_indent_inc();
+}
+
+static void pr_out_fmsg_group_end(struct dl *dl)
+{
+ __pr_out_newline();
+ __pr_out_indent_dec();
+}
+
+static void pr_out_fmsg_start_object(struct dl *dl, char **name)
+{
+ if (dl->json_output) {
+ pr_out_fmsg_name(dl, name);
+ open_json_object(NULL);
+ } else {
+ pr_out_fmsg_group_start(dl, name);
+ }
+}
+
+static void pr_out_fmsg_end_object(struct dl *dl)
+{
+ if (dl->json_output)
+ close_json_object();
+ else
+ pr_out_fmsg_group_end(dl);
+}
+
+static void pr_out_fmsg_start_array(struct dl *dl, char **name)
+{
+ if (dl->json_output) {
+ pr_out_fmsg_name(dl, name);
+ open_json_array(PRINT_JSON, NULL);
+ } else {
+ pr_out_fmsg_group_start(dl, name);
+ }
+}
+
+static void pr_out_fmsg_end_array(struct dl *dl)
+{
+ if (dl->json_output)
+ close_json_array(PRINT_JSON, NULL);
+ else
+ pr_out_fmsg_group_end(dl);
+}
+
static int cmd_fmsg_nest(struct fmsg_cb_data *fmsg_data, uint8_t nest_value,
bool start)
{
switch (value) {
case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
if (start)
- pr_out_entry_start(dl);
+ pr_out_fmsg_start_object(dl, &fmsg_data->name);
else
- pr_out_entry_end(dl);
+ pr_out_fmsg_end_object(dl);
break;
case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
break;
case DEVLINK_ATTR_FMSG_ARR_NEST_START:
- if (dl->json_output) {
- if (start)
- jsonw_start_array(dl->jw);
- else
- jsonw_end_array(dl->jw);
- } else {
- if (start) {
- __pr_out_newline();
- __pr_out_indent_inc();
- } else {
- __pr_out_indent_dec();
- }
- }
+ if (start)
+ pr_out_fmsg_start_array(dl, &fmsg_data->name);
+ else
+ pr_out_fmsg_end_array(dl);
break;
default:
return -EINVAL;
return err;
break;
case DEVLINK_ATTR_FMSG_OBJ_NAME:
- pr_out_name(dl, mnl_attr_get_str(nla_object));
+ free(fmsg_data->name);
+ fmsg_data->name = strdup(mnl_attr_get_str(nla_object));
+ if (!fmsg_data->name)
+ return -ENOMEM;
break;
case DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE:
fmsg_data->value_type = mnl_attr_get_u8(nla_object);
break;
case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA:
+ pr_out_fmsg_name(dl, &fmsg_data->name);
err = fmsg_value_show(dl, fmsg_data->value_type,
nla_object);
if (err != MNL_CB_OK)
return MNL_CB_OK;
}
-static int cmd_health_object_common(struct dl *dl, uint8_t cmd)
+static void cmd_fmsg_init(struct dl *dl, struct fmsg_cb_data *data)
+{
+ /* FMSG is dynamic: opening of an object or array causes a
+ * newline. JSON starts with an { or [, but plain text should
+ * not start with a new line. Ensure this by setting
+ * g_new_line_count to 1: avoiding newline before the first
+ * print.
+ */
+ g_new_line_count = 1;
+ data->name = NULL;
+ data->dl = dl;
+ INIT_LIST_HEAD(&data->entry_list);
+}
+
+static int cmd_health_object_common(struct dl *dl, uint8_t cmd, uint16_t flags)
{
struct fmsg_cb_data data;
struct nlmsghdr *nlh;
int err;
- nlh = mnlg_msg_prepare(dl->nlg, cmd, NLM_F_REQUEST | NLM_F_ACK);
+ nlh = mnlg_msg_prepare(dl->nlg, cmd, flags | NLM_F_REQUEST | NLM_F_ACK);
err = dl_argv_parse_put(nlh, dl,
DL_OPT_HANDLE | DL_OPT_HEALTH_REPORTER_NAME, 0);
if (err)
return err;
- data.dl = dl;
- TAILQ_INIT(&data.qhead);
+ cmd_fmsg_init(dl, &data);
err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_fmsg_object_cb, &data);
+ free(data.name);
return err;
}
static int cmd_health_dump_show(struct dl *dl)
{
- return cmd_health_object_common(dl, DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET);
+ return cmd_health_object_common(dl,
+ DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,
+ NLM_F_DUMP);
}
static int cmd_health_diagnose(struct dl *dl)
{
- return cmd_health_object_common(dl, DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE);
+ return cmd_health_object_common(dl,
+ DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE,
+ 0);
}
static int cmd_health_recover(struct dl *dl)
}
}
-static void format_logtime(uint64_t time_ms, char *ts_date, char *ts_time)
+static void pr_out_dump_reporter_format_logtime(struct dl *dl, const struct nlattr *attr)
{
+ char dump_date[HEALTH_REPORTER_TIMESTAMP_FMT_LEN];
+ char dump_time[HEALTH_REPORTER_TIMESTAMP_FMT_LEN];
+ uint64_t time_ms = mnl_attr_get_u64(attr);
struct sysinfo s_info;
struct tm *info;
time_t now, sec;
sec = now - s_info.uptime + time_ms / 1000;
info = localtime(&sec);
out:
- strftime(ts_date, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%Y-%m-%d", info);
- strftime(ts_time, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%H:%M:%S", info);
+ strftime(dump_date, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%Y-%m-%d", info);
+ strftime(dump_time, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%H:%M:%S", info);
+ check_indent_newline(dl);
+ print_string(PRINT_ANY, "last_dump_date", "last_dump_date %s", dump_date);
+ print_string(PRINT_ANY, "last_dump_time", " last_dump_time %s", dump_time);
+}
+
+static void pr_out_dump_report_timestamp(struct dl *dl, const struct nlattr *attr)
+{
+ char dump_date[HEALTH_REPORTER_TIMESTAMP_FMT_LEN];
+ char dump_time[HEALTH_REPORTER_TIMESTAMP_FMT_LEN];
+ time_t tv_sec;
+ struct tm *tm;
+ uint64_t ts;
+
+ ts = mnl_attr_get_u64(attr);
+ tv_sec = ts / 1000000000;
+ tm = localtime(&tv_sec);
+
+ strftime(dump_date, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%Y-%m-%d", tm);
+ strftime(dump_time, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%H:%M:%S", tm);
+
+ check_indent_newline(dl);
+ print_string(PRINT_ANY, "last_dump_date", "last_dump_date %s", dump_date);
+ print_string(PRINT_ANY, "last_dump_time", " last_dump_time %s", dump_time);
}
static void pr_out_health(struct dl *dl, struct nlattr **tb_health)
{
struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
enum devlink_health_reporter_state state;
- const struct nlattr *attr;
- uint64_t time_ms;
int err;
err = mnl_attr_parse_nested(tb_health[DEVLINK_ATTR_HEALTH_REPORTER],
pr_out_handle_start_arr(dl, tb_health);
- pr_out_str(dl, "name",
- mnl_attr_get_str(tb[DEVLINK_ATTR_HEALTH_REPORTER_NAME]));
+ check_indent_newline(dl);
+ print_string(PRINT_ANY, "reporter", "reporter %s",
+ mnl_attr_get_str(tb[DEVLINK_ATTR_HEALTH_REPORTER_NAME]));
if (!dl->json_output) {
__pr_out_newline();
__pr_out_indent_inc();
}
state = mnl_attr_get_u8(tb[DEVLINK_ATTR_HEALTH_REPORTER_STATE]);
- pr_out_str(dl, "state", health_state_name(state));
+ check_indent_newline(dl);
+ print_string(PRINT_ANY, "state", "state %s", health_state_name(state));
pr_out_u64(dl, "error",
mnl_attr_get_u64(tb[DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT]));
pr_out_u64(dl, "recover",
mnl_attr_get_u64(tb[DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT]));
- if (tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS]) {
- char dump_date[HEALTH_REPORTER_TIMESTAMP_FMT_LEN];
- char dump_time[HEALTH_REPORTER_TIMESTAMP_FMT_LEN];
-
- attr = tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS];
- time_ms = mnl_attr_get_u64(attr);
- format_logtime(time_ms, dump_date, dump_time);
-
- pr_out_str(dl, "last_dump_date", dump_date);
- pr_out_str(dl, "last_dump_time", dump_time);
- }
+ if (tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS])
+ pr_out_dump_report_timestamp(dl, tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS]);
+ else if (tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS])
+ pr_out_dump_reporter_format_logtime(dl, tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS]);
if (tb[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD])
pr_out_u64(dl, "grace_period",
mnl_attr_get_u64(tb[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]));
return -ENOENT;
}
+static const char *trap_type_name(uint8_t type)
+{
+ switch (type) {
+ case DEVLINK_TRAP_TYPE_DROP:
+ return "drop";
+ case DEVLINK_TRAP_TYPE_EXCEPTION:
+ return "exception";
+ default:
+ return "<unknown type>";
+ }
+}
+
+static const char *trap_action_name(uint8_t action)
+{
+ switch (action) {
+ case DEVLINK_TRAP_ACTION_DROP:
+ return "drop";
+ case DEVLINK_TRAP_ACTION_TRAP:
+ return "trap";
+ default:
+ return "<unknown action>";
+ }
+}
+
+static const char *trap_metadata_name(const struct nlattr *attr)
+{
+ switch (attr->nla_type) {
+ case DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT:
+ return "input_port";
+ default:
+ return "<unknown metadata type>";
+ }
+}
+static void pr_out_trap_metadata(struct dl *dl, struct nlattr *attr)
+{
+ struct nlattr *attr_metadata;
+
+ pr_out_array_start(dl, "metadata");
+ mnl_attr_for_each_nested(attr_metadata, attr) {
+ check_indent_newline(dl);
+ print_string(PRINT_ANY, NULL, "%s",
+ trap_metadata_name(attr_metadata));
+ }
+ pr_out_array_end(dl);
+}
+
+static void pr_out_trap(struct dl *dl, struct nlattr **tb, bool array)
+{
+ uint8_t action = mnl_attr_get_u8(tb[DEVLINK_ATTR_TRAP_ACTION]);
+ uint8_t type = mnl_attr_get_u8(tb[DEVLINK_ATTR_TRAP_TYPE]);
+
+ if (array)
+ pr_out_handle_start_arr(dl, tb);
+ else
+ __pr_out_handle_start(dl, tb, true, false);
+
+ check_indent_newline(dl);
+ print_string(PRINT_ANY, "name", "name %s",
+ mnl_attr_get_str(tb[DEVLINK_ATTR_TRAP_NAME]));
+ print_string(PRINT_ANY, "type", " type %s", trap_type_name(type));
+ pr_out_bool(dl, "generic", !!tb[DEVLINK_ATTR_TRAP_GENERIC]);
+ print_string(PRINT_ANY, "action", " action %s", trap_action_name(action));
+ print_string(PRINT_ANY, "group", " group %s",
+ mnl_attr_get_str(tb[DEVLINK_ATTR_TRAP_GROUP_NAME]));
+ if (dl->verbose)
+ pr_out_trap_metadata(dl, tb[DEVLINK_ATTR_TRAP_METADATA]);
+ pr_out_stats(dl, tb[DEVLINK_ATTR_STATS]);
+ pr_out_handle_end(dl);
+}
+
+static int cmd_trap_show_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
+ struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
+ struct dl *dl = data;
+
+ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
+ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
+ !tb[DEVLINK_ATTR_TRAP_NAME] || !tb[DEVLINK_ATTR_TRAP_TYPE] ||
+ !tb[DEVLINK_ATTR_TRAP_ACTION] ||
+ !tb[DEVLINK_ATTR_TRAP_GROUP_NAME] ||
+ !tb[DEVLINK_ATTR_TRAP_METADATA] || !tb[DEVLINK_ATTR_STATS])
+ return MNL_CB_ERROR;
+
+ pr_out_trap(dl, tb, true);
+
+ return MNL_CB_OK;
+}
+
+static void cmd_trap_help(void)
+{
+ pr_err("Usage: devlink trap set DEV trap TRAP [ action { trap | drop } ]\n");
+ pr_err(" devlink trap show [ DEV trap TRAP ]\n");
+ pr_err(" devlink trap group set DEV group GROUP [ action { trap | drop } ]\n");
+ pr_err(" devlink trap group show [ DEV group GROUP ]\n");
+}
+
+static int cmd_trap_show(struct dl *dl)
+{
+ uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
+ struct nlmsghdr *nlh;
+ int err;
+
+ if (dl_argc(dl) == 0)
+ flags |= NLM_F_DUMP;
+
+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_TRAP_GET, flags);
+
+ if (dl_argc(dl) > 0) {
+ err = dl_argv_parse_put(nlh, dl,
+ DL_OPT_HANDLE | DL_OPT_TRAP_NAME, 0);
+ if (err)
+ return err;
+ }
+
+ pr_out_section_start(dl, "trap");
+ err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_trap_show_cb, dl);
+ pr_out_section_end(dl);
+
+ return err;
+}
+
+static int cmd_trap_set(struct dl *dl)
+{
+ struct nlmsghdr *nlh;
+ int err;
+
+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_TRAP_SET,
+ NLM_F_REQUEST | NLM_F_ACK);
+
+ err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_TRAP_NAME,
+ DL_OPT_TRAP_ACTION);
+ if (err)
+ return err;
+
+ return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
+}
+
+static void pr_out_trap_group(struct dl *dl, struct nlattr **tb, bool array)
+{
+ if (array)
+ pr_out_handle_start_arr(dl, tb);
+ else
+ __pr_out_handle_start(dl, tb, true, false);
+
+ check_indent_newline(dl);
+ print_string(PRINT_ANY, "name", "name %s",
+ mnl_attr_get_str(tb[DEVLINK_ATTR_TRAP_GROUP_NAME]));
+ pr_out_bool(dl, "generic", !!tb[DEVLINK_ATTR_TRAP_GENERIC]);
+ pr_out_stats(dl, tb[DEVLINK_ATTR_STATS]);
+ pr_out_handle_end(dl);
+}
+
+static int cmd_trap_group_show_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
+ struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
+ struct dl *dl = data;
+
+ mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
+ if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
+ !tb[DEVLINK_ATTR_TRAP_GROUP_NAME] || !tb[DEVLINK_ATTR_STATS])
+ return MNL_CB_ERROR;
+
+ pr_out_trap_group(dl, tb, true);
+
+ return MNL_CB_OK;
+}
+
+static int cmd_trap_group_show(struct dl *dl)
+{
+ uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
+ struct nlmsghdr *nlh;
+ int err;
+
+ if (dl_argc(dl) == 0)
+ flags |= NLM_F_DUMP;
+
+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_TRAP_GROUP_GET, flags);
+
+ if (dl_argc(dl) > 0) {
+ err = dl_argv_parse_put(nlh, dl,
+ DL_OPT_HANDLE | DL_OPT_TRAP_GROUP_NAME,
+ 0);
+ if (err)
+ return err;
+ }
+
+ pr_out_section_start(dl, "trap_group");
+ err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_trap_group_show_cb, dl);
+ pr_out_section_end(dl);
+
+ return err;
+}
+
+static int cmd_trap_group_set(struct dl *dl)
+{
+ struct nlmsghdr *nlh;
+ int err;
+
+ nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_TRAP_GROUP_SET,
+ NLM_F_REQUEST | NLM_F_ACK);
+
+ err = dl_argv_parse_put(nlh, dl,
+ DL_OPT_HANDLE | DL_OPT_TRAP_GROUP_NAME,
+ DL_OPT_TRAP_ACTION);
+ if (err)
+ return err;
+
+ return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
+}
+
+static int cmd_trap_group(struct dl *dl)
+{
+ if (dl_argv_match(dl, "help")) {
+ cmd_trap_help();
+ return 0;
+ } else if (dl_argv_match(dl, "show") ||
+ dl_argv_match(dl, "list") || dl_no_arg(dl)) {
+ dl_arg_inc(dl);
+ return cmd_trap_group_show(dl);
+ } else if (dl_argv_match(dl, "set")) {
+ dl_arg_inc(dl);
+ return cmd_trap_group_set(dl);
+ }
+ pr_err("Command \"%s\" not found\n", dl_argv(dl));
+ return -ENOENT;
+}
+
+static int cmd_trap(struct dl *dl)
+{
+ if (dl_argv_match(dl, "help")) {
+ cmd_trap_help();
+ return 0;
+ } else if (dl_argv_match(dl, "show") ||
+ dl_argv_match(dl, "list") || dl_no_arg(dl)) {
+ dl_arg_inc(dl);
+ return cmd_trap_show(dl);
+ } else if (dl_argv_match(dl, "set")) {
+ dl_arg_inc(dl);
+ return cmd_trap_set(dl);
+ } else if (dl_argv_match(dl, "group")) {
+ dl_arg_inc(dl);
+ return cmd_trap_group(dl);
+ }
+ pr_err("Command \"%s\" not found\n", dl_argv(dl));
+ return -ENOENT;
+}
+
static void help(void)
{
pr_err("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n"
- " devlink [ -f[orce] ] -b[atch] filename\n"
- "where OBJECT := { dev | port | sb | monitor | dpipe | resource | region | health }\n"
- " OPTIONS := { -V[ersion] | -n[o-nice-names] | -j[son] | -p[retty] | -v[erbose] }\n");
+ " devlink [ -f[orce] ] -b[atch] filename -N[etns] netnsname\n"
+ "where OBJECT := { dev | port | sb | monitor | dpipe | resource | region | health | trap }\n"
+ " OPTIONS := { -V[ersion] | -n[o-nice-names] | -j[son] | -p[retty] | -v[erbose] -s[tatistics] }\n");
}
static int dl_cmd(struct dl *dl, int argc, char **argv)
} else if (dl_argv_match(dl, "health")) {
dl_arg_inc(dl);
return cmd_health(dl);
+ } else if (dl_argv_match(dl, "trap")) {
+ dl_arg_inc(dl);
+ return cmd_trap(dl);
}
pr_err("Object \"%s\" not found\n", dl_argv(dl));
return -ENOENT;
pr_err("Failed to create index map\n");
goto err_ifname_map_create;
}
- if (dl->json_output) {
- dl->jw = jsonw_new(stdout);
- if (!dl->jw) {
- pr_err("Failed to create JSON writer\n");
- goto err_json_new;
- }
- jsonw_pretty(dl->jw, dl->pretty_output);
- }
+ new_json_obj_plain(dl->json_output);
return 0;
-err_json_new:
- ifname_map_fini(dl);
err_ifname_map_create:
mnlg_socket_close(dl->nlg);
return err;
static void dl_fini(struct dl *dl)
{
- if (dl->json_output)
- jsonw_destroy(&dl->jw);
+ delete_json_obj_plain();
ifname_map_fini(dl);
mnlg_socket_close(dl->nlg);
}
{ "json", no_argument, NULL, 'j' },
{ "pretty", no_argument, NULL, 'p' },
{ "verbose", no_argument, NULL, 'v' },
+ { "statistics", no_argument, NULL, 's' },
+ { "Netns", required_argument, NULL, 'N' },
{ NULL, 0, NULL, 0 }
};
const char *batch_file = NULL;
return EXIT_FAILURE;
}
- while ((opt = getopt_long(argc, argv, "Vfb:njpv",
+ while ((opt = getopt_long(argc, argv, "Vfb:njpvsN:",
long_options, NULL)) >= 0) {
switch (opt) {
dl->json_output = true;
break;
case 'p':
- dl->pretty_output = true;
+ pretty = true;
break;
case 'v':
dl->verbose = true;
break;
+ case 's':
+ dl->stats = true;
+ break;
+ case 'N':
+ if (netns_switch(optarg)) {
+ ret = EXIT_FAILURE;
+ goto dl_free;
+ }
+ break;
default:
pr_err("Unknown option.\n");
help();