diff --git a/devlink/devlink.c b/devlink/devlink.c index 7888173f..d1795f61 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -2302,6 +2302,88 @@ static int dl_argv_dry_parse(struct dl *dl, uint64_t o_required, return err; } +/* List of extented handles with two slashes. */ +static const uint64_t dl_opt_extended_handle[] = { + DL_OPT_HANDLEP, + DL_OPT_HANDLE_REGION, + DL_OPT_PORT_FN_RATE_NODE_NAME, +}; + +static int dl_argv_parse_with_selector(struct dl *dl, uint16_t *flags, + uint8_t cmd, + uint64_t o_required, + uint64_t o_optional, + uint64_t o_dump_required, + uint64_t o_dump_optional) +{ + int err; + int i; + + if (dl_no_arg(dl)) + goto flag_set; + + /* In case the handle suggests it, do dry parsing first + * to see if all required options are there. Proceed with + * dump selector in case there are missing options on the + * command line. That means user provided partial + * object identification. + */ + + if ((o_required & (DL_OPT_HANDLE | DL_OPT_HANDLEP)) == + (DL_OPT_HANDLE | DL_OPT_HANDLEP)) { + /* Handle case when both devlink handle and port handle + * are allowed. Try both alone, if parsing of either + * is successful, we have a do parse case. + */ + err = dl_argv_dry_parse(dl, o_required & ~DL_OPT_HANDLEP, + o_optional); + if (err == -ENOENT) + goto dump_parse; + else if (!err) + goto do_parse; + err = dl_argv_dry_parse(dl, o_required & ~DL_OPT_HANDLE, + o_optional); + if (err == -ENOENT) + goto dump_parse; + goto do_parse; + } + + for (i = 0; i < ARRAY_SIZE(dl_opt_extended_handle); i++) { + uint64_t handle = dl_opt_extended_handle[i]; + + if ((o_required & handle) == handle) { + err = dl_argv_dry_parse(dl, (o_required & ~handle) | + DL_OPT_HANDLE, + o_optional); + if (err == -ENOENT || !err) + goto dump_parse; + goto do_parse; + } + } + + err = dl_argv_dry_parse(dl, o_required, o_optional); + if (err == -ENOENT) + goto dump_parse; + +do_parse: + return dl_argv_parse(dl, o_required, o_optional); + +dump_parse: + err = mnlu_gen_cmd_dump_policy(&dl->nlg, cmd); + if (err) { + pr_err("Dump selectors are not supported by kernel for this command\n"); + return -ENOTSUP; + } + + err = dl_argv_parse(dl, o_dump_required, o_dump_optional); + if (err) + return err; + +flag_set: + *flags |= NLM_F_DUMP; + return 0; +} + static void dl_function_attr_put(struct nlmsghdr *nlh, const struct dl_opts *opts) { @@ -3580,13 +3662,11 @@ static int cmd_dev_param_show(struct dl *dl) struct nlmsghdr *nlh; int err; - if (dl_no_arg(dl)) { - flags |= NLM_F_DUMP; - } else { - err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_PARAM_NAME, 0); - if (err) - return err; - } + err = dl_argv_parse_with_selector(dl, &flags, DEVLINK_CMD_PARAM_GET, + DL_OPT_HANDLE | DL_OPT_PARAM_NAME, 0, + DL_OPT_HANDLE, 0); + if (err) + return err; nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PARAM_GET, flags); @@ -4784,14 +4864,11 @@ static int cmd_port_show(struct dl *dl) uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; int err; - if (dl_no_arg(dl)) { - flags |= NLM_F_DUMP; - } - else { - err = dl_argv_parse(dl, DL_OPT_HANDLEP, 0); - if (err) - return err; - } + err = dl_argv_parse_with_selector(dl, &flags, DEVLINK_CMD_PORT_GET, + DL_OPT_HANDLEP, 0, + DL_OPT_HANDLE, 0); + if (err) + return err; nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_GET, flags); @@ -4860,14 +4937,12 @@ static int cmd_port_param_show(struct dl *dl) struct nlmsghdr *nlh; int err; - if (dl_no_arg(dl)) { - flags |= NLM_F_DUMP; - } - else { - err = dl_argv_parse(dl, DL_OPT_HANDLEP | DL_OPT_PARAM_NAME, 0); - if (err) - return err; - } + err = dl_argv_parse_with_selector(dl, &flags, + DEVLINK_CMD_PORT_PARAM_GET, + DL_OPT_HANDLE | DL_OPT_PARAM_NAME, 0, + DL_OPT_HANDLE | DL_OPT_HANDLEP, 0); + if (err) + return err; nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_PARAM_GET, flags); @@ -5234,16 +5309,9 @@ static int cmd_port_fn_rate_show(struct dl *dl) uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; int err; - if (dl_no_arg(dl)) { - flags |= NLM_F_DUMP; - } - else { - err = dl_argv_parse(dl, - DL_OPT_HANDLEP | DL_OPT_PORT_FN_RATE_NODE_NAME, - 0); - if (err) - return err; - } + err = dl_argv_parse_with_selector(dl, &flags, DEVLINK_CMD_RATE_GET, + DL_OPT_HANDLEP | DL_OPT_PORT_FN_RATE_NODE_NAME, + 0, DL_OPT_HANDLE, 0); nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RATE_GET, flags); @@ -5622,14 +5690,11 @@ static int cmd_linecard_show(struct dl *dl) uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; int err; - if (dl_no_arg(dl)) { - flags |= NLM_F_DUMP; - } - else { - err = dl_argv_parse(dl, DL_OPT_HANDLE, DL_OPT_LINECARD); - if (err) - return err; - } + err = dl_argv_parse_with_selector(dl, &flags, DEVLINK_CMD_LINECARD_GET, + DL_OPT_HANDLE | DL_OPT_LINECARD, 0, + DL_OPT_HANDLE, 0); + if (err) + return err; nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_LINECARD_GET, flags); @@ -5740,14 +5805,11 @@ static int cmd_sb_show(struct dl *dl) uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; int err; - if (dl_no_arg(dl)) { - flags |= NLM_F_DUMP; - } - else { - err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_SB, 0); - if (err) - return err; - } + err = dl_argv_parse_with_selector(dl, &flags, DEVLINK_CMD_SB_GET, + DL_OPT_HANDLE | DL_OPT_SB, 0, + DL_OPT_HANDLE, DL_OPT_SB); + if (err) + return err; nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_GET, flags); @@ -5819,15 +5881,12 @@ static int cmd_sb_pool_show(struct dl *dl) uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; int err; - if (dl_no_arg(dl)) { - flags |= NLM_F_DUMP; - } - else { - err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_SB | - DL_OPT_SB_POOL, 0); - if (err) - return err; - } + err = dl_argv_parse_with_selector(dl, &flags, DEVLINK_CMD_SB_POOL_GET, + DL_OPT_HANDLE | DL_OPT_SB | + DL_OPT_SB_POOL, 0, + DL_OPT_HANDLE, DL_OPT_SB); + if (err) + return err; nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_POOL_GET, flags); @@ -5908,15 +5967,13 @@ static int cmd_sb_port_pool_show(struct dl *dl) uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; int err; - if (dl_no_arg(dl)) { - flags |= NLM_F_DUMP; - } - else { - err = dl_argv_parse(dl, DL_OPT_HANDLEP | DL_OPT_SB | - DL_OPT_SB_POOL, 0); - if (err) - return err; - } + err = dl_argv_parse_with_selector(dl, &flags, + DEVLINK_CMD_SB_PORT_POOL_GET, + DL_OPT_HANDLEP | DL_OPT_SB | + DL_OPT_SB_POOL, 0, + DL_OPT_HANDLE | DL_OPT_HANDLEP, DL_OPT_SB); + if (err) + return err; nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags); @@ -6015,15 +6072,14 @@ static int cmd_sb_tc_bind_show(struct dl *dl) uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; int err; - if (dl_no_arg(dl)) { - flags |= NLM_F_DUMP; - } - else { - err = dl_argv_parse(dl, DL_OPT_HANDLEP | DL_OPT_SB | DL_OPT_SB_TC | - DL_OPT_SB_TYPE, 0); - if (err) - return err; - } + err = dl_argv_parse_with_selector(dl, &flags, + DEVLINK_CMD_SB_TC_POOL_BIND_GET, + DL_OPT_HANDLEP | DL_OPT_SB | + DL_OPT_SB_TC | DL_OPT_SB_TYPE, 0, + DL_OPT_HANDLE | DL_OPT_HANDLEP, + DL_OPT_SB); + if (err) + return err; nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags); @@ -8697,14 +8753,11 @@ static int cmd_region_show(struct dl *dl) uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; int err; - if (dl_no_arg(dl)) { - flags |= NLM_F_DUMP; - } - else { - err = dl_argv_parse(dl, DL_OPT_HANDLE_REGION, 0); - if (err) - return err; - } + err = dl_argv_parse_with_selector(dl, &flags, DEVLINK_CMD_REGION_GET, + DL_OPT_HANDLE_REGION, 0, + DL_OPT_HANDLE, 0); + if (err) + return err; nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_REGION_GET, flags); @@ -9388,19 +9441,20 @@ static int __cmd_health_show(struct dl *dl, bool show_device, bool show_port) uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; int err; - if (dl_no_arg(dl)) { - flags |= NLM_F_DUMP; - } else { + err = dl_argv_parse_with_selector(dl, &flags, + DEVLINK_CMD_HEALTH_REPORTER_GET, + DL_OPT_HANDLE | DL_OPT_HANDLEP | + DL_OPT_HEALTH_REPORTER_NAME, 0, + DL_OPT_HANDLE | DL_OPT_HANDLEP, 0); + if (err) + return err; + + if (!(flags & NLM_F_DUMP)) ctx.show_port = true; - err = dl_argv_parse(dl, - DL_OPT_HANDLE | DL_OPT_HANDLEP | - DL_OPT_HEALTH_REPORTER_NAME, 0); - if (err) - return err; - } nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_GET, flags); + dl_opts_put(nlh, dl); pr_out_section_start(dl, "health"); @@ -9582,14 +9636,11 @@ static int cmd_trap_show(struct dl *dl) struct nlmsghdr *nlh; int err; - if (dl_no_arg(dl)) { - flags |= NLM_F_DUMP; - } - else { - err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_TRAP_NAME, 0); - if (err) - return err; - } + err = dl_argv_parse_with_selector(dl, &flags, DEVLINK_CMD_TRAP_GET, + DL_OPT_HANDLE | DL_OPT_TRAP_NAME, 0, + DL_OPT_HANDLE, 0); + if (err) + return err; nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_TRAP_GET, flags); @@ -9660,15 +9711,12 @@ static int cmd_trap_group_show(struct dl *dl) struct nlmsghdr *nlh; int err; - if (dl_no_arg(dl)) { - flags |= NLM_F_DUMP; - } - else { - err = dl_argv_parse(dl, - DL_OPT_HANDLE | DL_OPT_TRAP_GROUP_NAME, 0); - if (err) - return err; - } + err = dl_argv_parse_with_selector(dl, &flags, + DEVLINK_CMD_TRAP_GROUP_GET, + DL_OPT_HANDLE | DL_OPT_TRAP_GROUP_NAME, 0, + DL_OPT_HANDLE, 0); + if (err) + return err; nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_TRAP_GROUP_GET, flags); @@ -9759,15 +9807,12 @@ static int cmd_trap_policer_show(struct dl *dl) struct nlmsghdr *nlh; int err; - if (dl_no_arg(dl)) { - flags |= NLM_F_DUMP; - } - else { - err = dl_argv_parse(dl, - DL_OPT_HANDLE | DL_OPT_TRAP_POLICER_ID, 0); - if (err) - return err; - } + err = dl_argv_parse_with_selector(dl, &flags, + DEVLINK_CMD_TRAP_POLICER_GET, + DL_OPT_HANDLE | DL_OPT_TRAP_POLICER_ID, 0, + DL_OPT_HANDLE, 0); + if (err) + return err; nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_TRAP_POLICER_GET, flags);