Thu, Feb 05, 2026 at 03:28:29PM +0100, [email protected] wrote:
>From: Or Har-Toov <[email protected]>
>
>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 <[email protected]>
>Reviewed-by: Shay Drori <[email protected]>
>Signed-off-by: Tariq Toukan <[email protected]>
>---
> 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-reply
>diff --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 - 1
>diff --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
>

Reply via email to