Re: [PATCH net-next V2 3/7] devlink: Add port resource netlink command
From: Jiri Pirko <jiri@resnulli.us>
Date: 2026-02-06 09:33:53
Also in:
linux-doc, linux-kselftest, linux-rdma, lkml
Thu, Feb 05, 2026 at 03:28:29PM +0100, tariqt@nvidia.com wrote:
quoted hunk ↗ jump to hunk
From: Or Har-Toov <redacted> Add support for userspace to query resources registered on devlink ports, allowing drivers to expose per-port resource limits and usage. Example output: $ devlink port resource show pci/0000:03:00.0/196608: name max_SFs size 20 unit entry pci/0000:03:00.1/262144: name max_SFs size 20 unit entry $ devlink port resource show pci/0000:03:00.0/196608 pci/0000:03:00.0/196608: name max_SFs size 20 unit entry Signed-off-by: Or Har-Toov <redacted> Reviewed-by: Shay Drori <redacted> Signed-off-by: Tariq Toukan <tariqt@nvidia.com> --- Documentation/netlink/specs/devlink.yaml | 23 ++++++ include/uapi/linux/devlink.h | 3 + net/devlink/netlink.c | 2 +- net/devlink/netlink_gen.c | 32 ++++++- net/devlink/netlink_gen.h | 6 +- net/devlink/resource.c | 101 +++++++++++++++++++++++ 6 files changed, 164 insertions(+), 3 deletions(-)diff --git a/Documentation/netlink/specs/devlink.yaml b/Documentation/netlink/specs/devlink.yaml index 837112da6738..0290db1b8393 100644 --- a/Documentation/netlink/specs/devlink.yaml +++ b/Documentation/netlink/specs/devlink.yaml@@ -2336,3 +2336,26 @@ operations: - bus-name - dev-name - port-index + + - + name: port-resource-get + doc: Get port resources. + attribute-set: devlink + dont-validate: [strict] + do: + pre: devlink-nl-pre-doit-port + post: devlink-nl-post-doit + request: + value: 85 + attributes: *port-id-attrs + reply: &port-resource-get-reply + value: 85 + attributes: + - bus-name + - dev-name + - port-index + - resource-list + dump: + request: + attributes: *dev-id-attrs + reply: *port-resource-get-replydiff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h index e7d6b6d13470..1cabd1f6cba0 100644 --- a/include/uapi/linux/devlink.h +++ b/include/uapi/linux/devlink.h@@ -141,6 +141,9 @@ enum devlink_command {DEVLINK_CMD_NOTIFY_FILTER_SET, + DEVLINK_CMD_PORT_RESOURCE_GET, /* can dump */ + DEVLINK_CMD_PORT_RESOURCE_SET, + /* add new commands above here */ __DEVLINK_CMD_MAX, DEVLINK_CMD_MAX = __DEVLINK_CMD_MAX - 1diff --git a/net/devlink/netlink.c b/net/devlink/netlink.c index 593605c1b1ef..c78c31779622 100644 --- a/net/devlink/netlink.c +++ b/net/devlink/netlink.c@@ -367,7 +367,7 @@ struct genl_family devlink_nl_family __ro_after_init = {.module = THIS_MODULE, .split_ops = devlink_nl_ops, .n_split_ops = ARRAY_SIZE(devlink_nl_ops), - .resv_start_op = DEVLINK_CMD_SELFTESTS_RUN + 1, + .resv_start_op = DEVLINK_CMD_PORT_RESOURCE_GET + 1, .mcgrps = devlink_nl_mcgrps, .n_mcgrps = ARRAY_SIZE(devlink_nl_mcgrps), .sock_priv_size = sizeof(struct devlink_nl_sock_priv),diff --git a/net/devlink/netlink_gen.c b/net/devlink/netlink_gen.c index f4c61c2b4f22..692d7862183a 100644 --- a/net/devlink/netlink_gen.c +++ b/net/devlink/netlink_gen.c@@ -604,8 +604,21 @@ static const struct nla_policy devlink_notify_filter_set_nl_policy[DEVLINK_ATTR_[DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32, }, }; +/* DEVLINK_CMD_PORT_RESOURCE_GET - do */ +static const struct nla_policy devlink_port_resource_get_do_nl_policy[DEVLINK_ATTR_PORT_INDEX + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32, }, +}; + +/* DEVLINK_CMD_PORT_RESOURCE_GET - dump */ +static const struct nla_policy devlink_port_resource_get_dump_nl_policy[DEVLINK_ATTR_DEV_NAME + 1] = { + [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, }, + [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, }, +}; + /* Ops table for devlink */ -const struct genl_split_ops devlink_nl_ops[74] = { +const struct genl_split_ops devlink_nl_ops[76] = { { .cmd = DEVLINK_CMD_GET, .validate = GENL_DONT_VALIDATE_STRICT,@@ -1284,4 +1297,21 @@ const struct genl_split_ops devlink_nl_ops[74] = {.maxattr = DEVLINK_ATTR_PORT_INDEX, .flags = GENL_CMD_CAP_DO, }, + { + .cmd = DEVLINK_CMD_PORT_RESOURCE_GET, + .validate = GENL_DONT_VALIDATE_STRICT, + .pre_doit = devlink_nl_pre_doit_port, + .doit = devlink_nl_port_resource_get_doit, + .post_doit = devlink_nl_post_doit, + .policy = devlink_port_resource_get_do_nl_policy, + .maxattr = DEVLINK_ATTR_PORT_INDEX, + .flags = GENL_CMD_CAP_DO, + }, + { + .cmd = DEVLINK_CMD_PORT_RESOURCE_GET, + .dumpit = devlink_nl_port_resource_get_dumpit, + .policy = devlink_port_resource_get_dump_nl_policy, + .maxattr = DEVLINK_ATTR_DEV_NAME, + .flags = GENL_CMD_CAP_DUMP, + }, };diff --git a/net/devlink/netlink_gen.h b/net/devlink/netlink_gen.h index 2817d53a0eba..204a665d2fd2 100644 --- a/net/devlink/netlink_gen.h +++ b/net/devlink/netlink_gen.h@@ -18,7 +18,7 @@ extern const struct nla_policy devlink_dl_rate_tc_bws_nl_policy[DEVLINK_RATE_TC_extern const struct nla_policy devlink_dl_selftest_id_nl_policy[DEVLINK_ATTR_SELFTEST_ID_FLASH + 1]; /* Ops table for devlink */ -extern const struct genl_split_ops devlink_nl_ops[74]; +extern const struct genl_split_ops devlink_nl_ops[76]; int devlink_nl_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, struct genl_info *info);@@ -146,5 +146,9 @@ int devlink_nl_selftests_get_dumpit(struct sk_buff *skb,int devlink_nl_selftests_run_doit(struct sk_buff *skb, struct genl_info *info); int devlink_nl_notify_filter_set_doit(struct sk_buff *skb, struct genl_info *info); +int devlink_nl_port_resource_get_doit(struct sk_buff *skb, + struct genl_info *info); +int devlink_nl_port_resource_get_dumpit(struct sk_buff *skb, + struct netlink_callback *cb); #endif /* _LINUX_DEVLINK_GEN_H */diff --git a/net/devlink/resource.c b/net/devlink/resource.c index 1b06a1f408fa..42ad7c96a740 100644 --- a/net/devlink/resource.c +++ b/net/devlink/resource.c@@ -227,6 +227,7 @@ static int devlink_resource_fill(struct genl_info *info,struct list_head *resource_list, enum devlink_command cmd, int flags) { + struct devlink_port *devlink_port = info->user_ptr[1]; struct devlink *devlink = info->user_ptr[0]; struct devlink_resource *resource; struct nlattr *resources_attr;@@ -257,6 +258,10 @@ static int devlink_resource_fill(struct genl_info *info,if (devlink_nl_put_handle(skb, devlink)) goto nla_put_failure; + if (devlink_port && nla_put_u32(skb, DEVLINK_ATTR_PORT_INDEX, + devlink_port->index)) + goto nla_put_failure; + resources_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_RESOURCE_LIST); if (!resources_attr)@@ -576,3 +581,99 @@ void devl_port_resources_unregister(struct devlink_port *devlink_port)&devlink_port->resource_list); } EXPORT_SYMBOL_GPL(devl_port_resources_unregister); + +static int devlink_nl_port_resource_fill(struct sk_buff *msg, + struct devlink_port *devlink_port, + enum devlink_command cmd, + u32 portid, u32 seq, int flags) +{ + struct devlink *devlink = devlink_port->devlink; + struct devlink_resource *resource; + struct nlattr *resources_attr; + void *hdr; + + if (list_empty(&devlink_port->resource_list)) + return 0; + + hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); + if (!hdr) + return -EMSGSIZE; + + if (devlink_nl_put_handle(msg, devlink)) + goto nla_put_failure; + if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index)) + goto nla_put_failure; + + resources_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_RESOURCE_LIST); + if (!resources_attr) + goto nla_put_failure; + + list_for_each_entry(resource, &devlink_port->resource_list, list) { + if (devlink_resource_put(devlink, msg, resource)) { + nla_nest_cancel(msg, resources_attr); + goto nla_put_failure; + } + } + nla_nest_end(msg, resources_attr); + genlmsg_end(msg, hdr); + return 0; + +nla_put_failure: + genlmsg_cancel(msg, hdr); + return -EMSGSIZE;
Why you don't unify this function with existing devlink_resource_fill()? Unnecessary code duplication, plus devlink_resource_fill() already know how to handle multipart message. This is related to my request to implement dump for devlink dev resources. I would like to see the code unification for dump ops as well. Thanks!
+}
+
+int devlink_nl_port_resource_get_doit(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct devlink_port *devlink_port = info->user_ptr[1];
+ struct sk_buff *msg;
+ int err;
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ err = devlink_nl_port_resource_fill(msg, devlink_port,
+ DEVLINK_CMD_PORT_RESOURCE_GET,
+ info->snd_portid, info->snd_seq, 0);
+ if (err) {
+ nlmsg_free(msg);
+ return err;
+ }
+
+ return genlmsg_reply(msg, info);
+}
+
+static int
+devlink_nl_port_resource_get_dump_one(struct sk_buff *msg,
+ struct devlink *devlink,
+ struct netlink_callback *cb, int flags)
+{
+ enum devlink_command cmd = DEVLINK_CMD_PORT_RESOURCE_GET;
+ struct devlink_nl_dump_state *state = devlink_dump_state(cb);
+ struct devlink_port *devlink_port;
+ unsigned long port_index;
+ int err;
+
+ xa_for_each_start(&devlink->ports, port_index, devlink_port,
+ state->idx) {
+ err = devlink_nl_port_resource_fill(msg, devlink_port,
+ cmd,
+ NETLINK_CB(cb->skb).portid,
+ cb->nlh->nlmsg_seq, flags);
+ if (err) {
+ state->idx = port_index;
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+int devlink_nl_port_resource_get_dumpit(struct sk_buff *skb,
+ struct netlink_callback *cb)
+{
+ return devlink_nl_dumpit(skb, cb,
+ devlink_nl_port_resource_get_dump_one);
+}
--
2.44.0