Merge branch 'devlink-reload' into next
Signed-off-by: David Ahern <dsahern@gmail.com>
This commit is contained in:
commit
6e9bfdcdde
|
|
@ -304,6 +304,8 @@ static void ifname_map_free(struct ifname_map *ifname_map)
|
|||
#define DL_OPT_HEALTH_REPORTER_AUTO_DUMP BIT(37)
|
||||
#define DL_OPT_PORT_FUNCTION_HW_ADDR BIT(38)
|
||||
#define DL_OPT_FLASH_OVERWRITE BIT(39)
|
||||
#define DL_OPT_RELOAD_ACTION BIT(40)
|
||||
#define DL_OPT_RELOAD_LIMIT BIT(41)
|
||||
|
||||
struct dl_opts {
|
||||
uint64_t present; /* flags of present items */
|
||||
|
|
@ -352,6 +354,8 @@ struct dl_opts {
|
|||
char port_function_hw_addr[MAX_ADDR_LEN];
|
||||
uint32_t port_function_hw_addr_len;
|
||||
uint32_t overwrite_mask;
|
||||
enum devlink_reload_action reload_action;
|
||||
enum devlink_reload_limit reload_limit;
|
||||
};
|
||||
|
||||
struct dl {
|
||||
|
|
@ -678,6 +682,15 @@ static const enum mnl_attr_data_type devlink_policy[DEVLINK_ATTR_MAX + 1] = {
|
|||
[DEVLINK_ATTR_TRAP_METADATA] = MNL_TYPE_NESTED,
|
||||
[DEVLINK_ATTR_TRAP_GROUP_NAME] = MNL_TYPE_STRING,
|
||||
[DEVLINK_ATTR_RELOAD_FAILED] = MNL_TYPE_U8,
|
||||
[DEVLINK_ATTR_DEV_STATS] = MNL_TYPE_NESTED,
|
||||
[DEVLINK_ATTR_RELOAD_STATS] = MNL_TYPE_NESTED,
|
||||
[DEVLINK_ATTR_RELOAD_STATS_ENTRY] = MNL_TYPE_NESTED,
|
||||
[DEVLINK_ATTR_RELOAD_ACTION] = MNL_TYPE_U8,
|
||||
[DEVLINK_ATTR_RELOAD_STATS_LIMIT] = MNL_TYPE_U8,
|
||||
[DEVLINK_ATTR_RELOAD_STATS_VALUE] = MNL_TYPE_U32,
|
||||
[DEVLINK_ATTR_REMOTE_RELOAD_STATS] = MNL_TYPE_NESTED,
|
||||
[DEVLINK_ATTR_RELOAD_ACTION_INFO] = MNL_TYPE_NESTED,
|
||||
[DEVLINK_ATTR_RELOAD_ACTION_STATS] = MNL_TYPE_NESTED,
|
||||
[DEVLINK_ATTR_TRAP_POLICER_ID] = MNL_TYPE_U32,
|
||||
[DEVLINK_ATTR_TRAP_POLICER_RATE] = MNL_TYPE_U64,
|
||||
[DEVLINK_ATTR_TRAP_POLICER_BURST] = MNL_TYPE_U64,
|
||||
|
|
@ -1344,6 +1357,32 @@ static int hw_addr_parse(const char *addrstr, char *hw_addr, uint32_t *len)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int reload_action_get(struct dl *dl, const char *actionstr,
|
||||
enum devlink_reload_action *action)
|
||||
{
|
||||
if (strcmp(actionstr, "driver_reinit") == 0) {
|
||||
*action = DEVLINK_RELOAD_ACTION_DRIVER_REINIT;
|
||||
} else if (strcmp(actionstr, "fw_activate") == 0) {
|
||||
*action = DEVLINK_RELOAD_ACTION_FW_ACTIVATE;
|
||||
} else {
|
||||
pr_err("Unknown reload action \"%s\"\n", actionstr);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reload_limit_get(struct dl *dl, const char *limitstr,
|
||||
enum devlink_reload_limit *limit)
|
||||
{
|
||||
if (strcmp(limitstr, "no_reset") == 0) {
|
||||
*limit = DEVLINK_RELOAD_LIMIT_NO_RESET;
|
||||
} else {
|
||||
pr_err("Unknown reload limit \"%s\"\n", limitstr);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dl_args_metadata {
|
||||
uint64_t o_flag;
|
||||
char err_msg[DL_ARGS_REQUIRED_MAX_ERR_LEN];
|
||||
|
|
@ -1730,6 +1769,30 @@ static int dl_argv_parse(struct dl *dl, uint64_t o_required,
|
|||
opts->netns_is_pid = true;
|
||||
}
|
||||
o_found |= DL_OPT_NETNS;
|
||||
} else if (dl_argv_match(dl, "action") &&
|
||||
(o_all & DL_OPT_RELOAD_ACTION)) {
|
||||
const char *actionstr;
|
||||
|
||||
dl_arg_inc(dl);
|
||||
err = dl_argv_str(dl, &actionstr);
|
||||
if (err)
|
||||
return err;
|
||||
err = reload_action_get(dl, actionstr, &opts->reload_action);
|
||||
if (err)
|
||||
return err;
|
||||
o_found |= DL_OPT_RELOAD_ACTION;
|
||||
} else if (dl_argv_match(dl, "limit") &&
|
||||
(o_all & DL_OPT_RELOAD_LIMIT)) {
|
||||
const char *limitstr;
|
||||
|
||||
dl_arg_inc(dl);
|
||||
err = dl_argv_str(dl, &limitstr);
|
||||
if (err)
|
||||
return err;
|
||||
err = reload_limit_get(dl, limitstr, &opts->reload_limit);
|
||||
if (err)
|
||||
return err;
|
||||
o_found |= DL_OPT_RELOAD_LIMIT;
|
||||
} else if (dl_argv_match(dl, "policer") &&
|
||||
(o_all & DL_OPT_TRAP_POLICER_ID)) {
|
||||
dl_arg_inc(dl);
|
||||
|
|
@ -1810,6 +1873,16 @@ dl_flash_update_overwrite_put(struct nlmsghdr *nlh, const struct dl_opts *opts)
|
|||
sizeof(overwrite_mask), &overwrite_mask);
|
||||
}
|
||||
|
||||
static void
|
||||
dl_reload_limits_put(struct nlmsghdr *nlh, const struct dl_opts *opts)
|
||||
{
|
||||
struct nla_bitfield32 limits;
|
||||
|
||||
limits.selector = DEVLINK_RELOAD_LIMITS_VALID_MASK;
|
||||
limits.value = BIT(opts->reload_limit);
|
||||
mnl_attr_put(nlh, DEVLINK_ATTR_RELOAD_LIMITS, sizeof(limits), &limits);
|
||||
}
|
||||
|
||||
static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl)
|
||||
{
|
||||
struct dl_opts *opts = &dl->opts;
|
||||
|
|
@ -1926,6 +1999,11 @@ static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl)
|
|||
opts->netns_is_pid ? DEVLINK_ATTR_NETNS_PID :
|
||||
DEVLINK_ATTR_NETNS_FD,
|
||||
opts->netns);
|
||||
if (opts->present & DL_OPT_RELOAD_ACTION)
|
||||
mnl_attr_put_u8(nlh, DEVLINK_ATTR_RELOAD_ACTION,
|
||||
opts->reload_action);
|
||||
if (opts->present & DL_OPT_RELOAD_LIMIT)
|
||||
dl_reload_limits_put(nlh, opts);
|
||||
if (opts->present & DL_OPT_TRAP_POLICER_ID)
|
||||
mnl_attr_put_u32(nlh, DEVLINK_ATTR_TRAP_POLICER_ID,
|
||||
opts->trap_policer_id);
|
||||
|
|
@ -1998,6 +2076,7 @@ static void cmd_dev_help(void)
|
|||
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 [ netns { PID | NAME | ID } ]\n");
|
||||
pr_err(" [ action { driver_reinit | fw_activate } ] [ limit no_reset ]\n");
|
||||
pr_err(" devlink dev info [ DEV ]\n");
|
||||
pr_err(" devlink dev flash DEV file PATH [ component NAME ] [ overwrite SECTION ]\n");
|
||||
}
|
||||
|
|
@ -2289,6 +2368,30 @@ static const char *param_cmode_name(uint8_t cmode)
|
|||
}
|
||||
}
|
||||
|
||||
static const char *reload_action_name(uint8_t reload_action)
|
||||
{
|
||||
switch (reload_action) {
|
||||
case DEVLINK_RELOAD_ACTION_DRIVER_REINIT:
|
||||
return "driver_reinit";
|
||||
case DEVLINK_RELOAD_ACTION_FW_ACTIVATE:
|
||||
return "fw_activate";
|
||||
default:
|
||||
return "<unknown reload action>";
|
||||
}
|
||||
}
|
||||
|
||||
static const char *reload_limit_name(uint8_t reload_limit)
|
||||
{
|
||||
switch (reload_limit) {
|
||||
case DEVLINK_RELOAD_LIMIT_UNSPEC:
|
||||
return "unspecified";
|
||||
case DEVLINK_RELOAD_LIMIT_NO_RESET:
|
||||
return "no_reset";
|
||||
default:
|
||||
return "<unknown reload action>";
|
||||
}
|
||||
}
|
||||
|
||||
static const char *eswitch_mode_name(uint32_t mode)
|
||||
{
|
||||
switch (mode) {
|
||||
|
|
@ -2893,29 +2996,119 @@ static int cmd_dev_param(struct dl *dl)
|
|||
pr_err("Command \"%s\" not found\n", dl_argv(dl));
|
||||
return -ENOENT;
|
||||
}
|
||||
static int cmd_dev_show_cb(const struct nlmsghdr *nlh, void *data)
|
||||
{
|
||||
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;
|
||||
static void pr_out_action_stats(struct dl *dl, struct nlattr *action_stats)
|
||||
{
|
||||
struct nlattr *tb_stats_entry[DEVLINK_ATTR_MAX + 1] = {};
|
||||
struct nlattr *nla_reload_stats_entry, *nla_limit, *nla_value;
|
||||
enum devlink_reload_limit limit;
|
||||
uint32_t value;
|
||||
int err;
|
||||
|
||||
mnl_attr_for_each_nested(nla_reload_stats_entry, action_stats) {
|
||||
err = mnl_attr_parse_nested(nla_reload_stats_entry, attr_cb,
|
||||
tb_stats_entry);
|
||||
if (err != MNL_CB_OK)
|
||||
return;
|
||||
|
||||
nla_limit = tb_stats_entry[DEVLINK_ATTR_RELOAD_STATS_LIMIT];
|
||||
nla_value = tb_stats_entry[DEVLINK_ATTR_RELOAD_STATS_VALUE];
|
||||
if (!nla_limit || !nla_value)
|
||||
return;
|
||||
|
||||
check_indent_newline(dl);
|
||||
limit = mnl_attr_get_u8(nla_limit);
|
||||
value = mnl_attr_get_u32(nla_value);
|
||||
print_uint_name_value(reload_limit_name(limit), value);
|
||||
}
|
||||
}
|
||||
|
||||
static void pr_out_reload_stats(struct dl *dl, struct nlattr *reload_stats)
|
||||
{
|
||||
struct nlattr *nla_action_info, *nla_action, *nla_action_stats;
|
||||
struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
|
||||
enum devlink_reload_action action;
|
||||
int err;
|
||||
|
||||
mnl_attr_for_each_nested(nla_action_info, reload_stats) {
|
||||
err = mnl_attr_parse_nested(nla_action_info, attr_cb, tb);
|
||||
if (err != MNL_CB_OK)
|
||||
return;
|
||||
nla_action = tb[DEVLINK_ATTR_RELOAD_ACTION];
|
||||
nla_action_stats = tb[DEVLINK_ATTR_RELOAD_ACTION_STATS];
|
||||
if (!nla_action || !nla_action_stats)
|
||||
return;
|
||||
|
||||
action = mnl_attr_get_u8(nla_action);
|
||||
pr_out_object_start(dl, reload_action_name(action));
|
||||
pr_out_action_stats(dl, nla_action_stats);
|
||||
pr_out_object_end(dl);
|
||||
}
|
||||
}
|
||||
|
||||
static void pr_out_reload_data(struct dl *dl, struct nlattr **tb)
|
||||
{
|
||||
struct nlattr *nla_reload_stats, *nla_remote_reload_stats;
|
||||
struct nlattr *tb_stats[DEVLINK_ATTR_MAX + 1] = {};
|
||||
uint8_t reload_failed = 0;
|
||||
int err;
|
||||
|
||||
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);
|
||||
check_indent_newline(dl);
|
||||
print_bool(PRINT_ANY, "reload_failed", "reload_failed %s", true);
|
||||
}
|
||||
if (!tb[DEVLINK_ATTR_DEV_STATS] || !dl->stats)
|
||||
return;
|
||||
err = mnl_attr_parse_nested(tb[DEVLINK_ATTR_DEV_STATS], attr_cb,
|
||||
tb_stats);
|
||||
if (err != MNL_CB_OK)
|
||||
return;
|
||||
|
||||
pr_out_object_start(dl, "stats");
|
||||
|
||||
nla_reload_stats = tb_stats[DEVLINK_ATTR_RELOAD_STATS];
|
||||
if (nla_reload_stats) {
|
||||
pr_out_object_start(dl, "reload");
|
||||
pr_out_reload_stats(dl, nla_reload_stats);
|
||||
pr_out_object_end(dl);
|
||||
}
|
||||
nla_remote_reload_stats = tb_stats[DEVLINK_ATTR_REMOTE_RELOAD_STATS];
|
||||
if (nla_remote_reload_stats) {
|
||||
pr_out_object_start(dl, "remote_reload");
|
||||
pr_out_reload_stats(dl, nla_remote_reload_stats);
|
||||
pr_out_object_end(dl);
|
||||
}
|
||||
|
||||
pr_out_object_end(dl);
|
||||
}
|
||||
|
||||
|
||||
static void pr_out_dev(struct dl *dl, struct nlattr **tb)
|
||||
{
|
||||
if ((tb[DEVLINK_ATTR_RELOAD_FAILED] && mnl_attr_get_u8(tb[DEVLINK_ATTR_RELOAD_FAILED])) ||
|
||||
(tb[DEVLINK_ATTR_DEV_STATS] && dl->stats)) {
|
||||
__pr_out_handle_start(dl, tb, true, false);
|
||||
pr_out_reload_data(dl, tb);
|
||||
pr_out_handle_end(dl);
|
||||
} else {
|
||||
pr_out_handle(dl, tb);
|
||||
}
|
||||
}
|
||||
|
||||
static int cmd_dev_show_cb(const struct nlmsghdr *nlh, void *data)
|
||||
{
|
||||
struct dl *dl = data;
|
||||
struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
|
||||
struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
|
||||
|
||||
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);
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
|
|
@ -2942,6 +3135,57 @@ static int cmd_dev_show(struct dl *dl)
|
|||
return err;
|
||||
}
|
||||
|
||||
static void pr_out_reload_actions_performed(struct dl *dl, struct nlattr **tb)
|
||||
{
|
||||
struct nlattr *nla_actions_performed;
|
||||
struct nla_bitfield32 *actions;
|
||||
uint32_t actions_performed;
|
||||
uint16_t len;
|
||||
int action;
|
||||
|
||||
if (!tb[DEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED])
|
||||
return;
|
||||
|
||||
nla_actions_performed = tb[DEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED];
|
||||
len = mnl_attr_get_payload_len(nla_actions_performed);
|
||||
if (len != sizeof(*actions))
|
||||
return;
|
||||
actions = mnl_attr_get_payload(nla_actions_performed);
|
||||
if (!actions)
|
||||
return;
|
||||
g_new_line_count = 1; /* Avoid extra new line in non-json print */
|
||||
pr_out_array_start(dl, "reload_actions_performed");
|
||||
actions_performed = actions->value & actions->selector;
|
||||
for (action = 0; action <= DEVLINK_RELOAD_ACTION_MAX; action++) {
|
||||
if (BIT(action) & actions_performed) {
|
||||
check_indent_newline(dl);
|
||||
print_string(PRINT_ANY, NULL, "%s",
|
||||
reload_action_name(action));
|
||||
}
|
||||
}
|
||||
pr_out_array_end(dl);
|
||||
if (!dl->json_output)
|
||||
__pr_out_newline();
|
||||
}
|
||||
|
||||
static int cmd_dev_reload_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_RELOAD_ACTIONS_PERFORMED])
|
||||
return MNL_CB_ERROR;
|
||||
|
||||
pr_out_section_start(dl, "reload");
|
||||
pr_out_reload_actions_performed(dl, tb);
|
||||
pr_out_section_end(dl);
|
||||
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
static int cmd_dev_reload(struct dl *dl)
|
||||
{
|
||||
struct nlmsghdr *nlh;
|
||||
|
|
@ -2955,11 +3199,13 @@ 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, DL_OPT_NETNS);
|
||||
err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE,
|
||||
DL_OPT_NETNS | DL_OPT_RELOAD_ACTION |
|
||||
DL_OPT_RELOAD_LIMIT);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
|
||||
return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_reload_cb, dl);
|
||||
}
|
||||
|
||||
static void pr_out_versions_single(struct dl *dl, const struct nlmsghdr *nlh,
|
||||
|
|
@ -4708,7 +4954,8 @@ 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_handle(dl, tb);
|
||||
dl->stats = true;
|
||||
pr_out_dev(dl, tb);
|
||||
pr_out_mon_footer();
|
||||
break;
|
||||
case DEVLINK_CMD_PORT_GET: /* fall through */
|
||||
|
|
|
|||
|
|
@ -63,6 +63,10 @@ devlink-dev \- devlink device configuration
|
|||
[
|
||||
.B netns
|
||||
.RI "{ " PID " | " NAME " | " ID " }"
|
||||
] [
|
||||
.BR action " { " driver_reinit " | " fw_activate " }"
|
||||
] [
|
||||
.B limit no_reset
|
||||
]
|
||||
|
||||
.ti -8
|
||||
|
|
@ -173,6 +177,36 @@ If this argument is omitted all parameters supported by devlink devices are list
|
|||
.RI { " PID " | " NAME " | " ID " }
|
||||
- Specifies the network namespace to reload into, either by pid, name or id.
|
||||
|
||||
.BR action " { " driver_reinit " | " fw_activate " }"
|
||||
- Specifies the reload action required.
|
||||
If this argument is omitted
|
||||
.I driver_reinit
|
||||
action will be used.
|
||||
Note that even though user asks for a specific action, the driver implementation
|
||||
might require to perform another action alongside with it. For example, some
|
||||
driver do not support driver reinitialization being performed without fw
|
||||
activation. Therefore, the devlink reload command returns the list of actions
|
||||
which were actrually performed.
|
||||
|
||||
.I driver_reinit
|
||||
- Driver entities re-initialization, applying devlink-param and
|
||||
devlink-resource values.
|
||||
|
||||
.I fw_activate
|
||||
- Activates new firmware if such image is stored and pending activation. If no
|
||||
limitation specified this action may involve firmware reset. If no new image
|
||||
pending this action will reload current firmware image.
|
||||
|
||||
.B limit no_reset
|
||||
- Specifies limitation on reload action.
|
||||
If this argument is omitted limit is unspecificed and the reload action is not
|
||||
limited. In such case driver implementation may include reset or downtime as
|
||||
needed to perform the actions.
|
||||
|
||||
.I no_reset
|
||||
- No reset allowed, no down time allowed, no link flap and no configuration is
|
||||
lost.
|
||||
|
||||
.SS devlink dev info - display device information.
|
||||
Display device information provided by the driver. This command can be used
|
||||
to query versions of the hardware components or device components which
|
||||
|
|
|
|||
Loading…
Reference in New Issue