devlink: Add support for region get command
authorAlex Vesker <valex@mellanox.com>
Thu, 12 Jul 2018 12:13:11 +0000 (15:13 +0300)
committerDavid S. Miller <davem@davemloft.net>
Fri, 13 Jul 2018 00:37:13 +0000 (17:37 -0700)
Add support for DEVLINK_CMD_REGION_GET command which is used for
querying for the supported DEV/REGION values of devlink devices.
The support is both for doit and dumpit.

Reply includes:
  BUS_NAME, DEVICE_NAME, REGION_NAME, REGION_SIZE

Signed-off-by: Alex Vesker <valex@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/uapi/linux/devlink.h
net/core/devlink.c

index 68641fb..28bfa8a 100644 (file)
@@ -83,6 +83,9 @@ enum devlink_command {
        DEVLINK_CMD_PARAM_NEW,
        DEVLINK_CMD_PARAM_DEL,
 
+       DEVLINK_CMD_REGION_GET,
+       DEVLINK_CMD_REGION_SET,
+
        /* add new commands above here */
        __DEVLINK_CMD_MAX,
        DEVLINK_CMD_MAX = __DEVLINK_CMD_MAX - 1
@@ -262,6 +265,9 @@ enum devlink_attr {
        DEVLINK_ATTR_PARAM_VALUE_DATA,          /* dynamic */
        DEVLINK_ATTR_PARAM_VALUE_CMODE,         /* u8 */
 
+       DEVLINK_ATTR_REGION_NAME,               /* string */
+       DEVLINK_ATTR_REGION_SIZE,               /* u64 */
+
        /* add new attributes above here, update the policy in devlink.c */
 
        __DEVLINK_ATTR_MAX,
index 7d09fe6..221ddb6 100644 (file)
@@ -3149,6 +3149,111 @@ static void devlink_param_unregister_one(struct devlink *devlink,
        kfree(param_item);
 }
 
+static int devlink_nl_region_fill(struct sk_buff *msg, struct devlink *devlink,
+                                 enum devlink_command cmd, u32 portid,
+                                 u32 seq, int flags,
+                                 struct devlink_region *region)
+{
+       void *hdr;
+       int err;
+
+       hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
+       if (!hdr)
+               return -EMSGSIZE;
+
+       err = devlink_nl_put_handle(msg, devlink);
+       if (err)
+               goto nla_put_failure;
+
+       err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME, region->name);
+       if (err)
+               goto nla_put_failure;
+
+       err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
+                               region->size,
+                               DEVLINK_ATTR_PAD);
+       if (err)
+               goto nla_put_failure;
+
+       genlmsg_end(msg, hdr);
+       return 0;
+
+nla_put_failure:
+       genlmsg_cancel(msg, hdr);
+       return err;
+}
+
+static int devlink_nl_cmd_region_get_doit(struct sk_buff *skb,
+                                         struct genl_info *info)
+{
+       struct devlink *devlink = info->user_ptr[0];
+       struct devlink_region *region;
+       const char *region_name;
+       struct sk_buff *msg;
+       int err;
+
+       if (!info->attrs[DEVLINK_ATTR_REGION_NAME])
+               return -EINVAL;
+
+       region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
+       region = devlink_region_get_by_name(devlink, region_name);
+       if (!region)
+               return -EINVAL;
+
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       err = devlink_nl_region_fill(msg, devlink, DEVLINK_CMD_REGION_GET,
+                                    info->snd_portid, info->snd_seq, 0,
+                                    region);
+       if (err) {
+               nlmsg_free(msg);
+               return err;
+       }
+
+       return genlmsg_reply(msg, info);
+}
+
+static int devlink_nl_cmd_region_get_dumpit(struct sk_buff *msg,
+                                           struct netlink_callback *cb)
+{
+       struct devlink_region *region;
+       struct devlink *devlink;
+       int start = cb->args[0];
+       int idx = 0;
+       int err;
+
+       mutex_lock(&devlink_mutex);
+       list_for_each_entry(devlink, &devlink_list, list) {
+               if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
+                       continue;
+
+               mutex_lock(&devlink->lock);
+               list_for_each_entry(region, &devlink->region_list, list) {
+                       if (idx < start) {
+                               idx++;
+                               continue;
+                       }
+                       err = devlink_nl_region_fill(msg, devlink,
+                                                    DEVLINK_CMD_REGION_GET,
+                                                    NETLINK_CB(cb->skb).portid,
+                                                    cb->nlh->nlmsg_seq,
+                                                    NLM_F_MULTI, region);
+                       if (err) {
+                               mutex_unlock(&devlink->lock);
+                               goto out;
+                       }
+                       idx++;
+               }
+               mutex_unlock(&devlink->lock);
+       }
+out:
+       mutex_unlock(&devlink_mutex);
+       cb->args[0] = idx;
+       return msg->len;
+}
+
 static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
        [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING },
        [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING },
@@ -3172,6 +3277,7 @@ static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
        [DEVLINK_ATTR_PARAM_NAME] = { .type = NLA_NUL_STRING },
        [DEVLINK_ATTR_PARAM_TYPE] = { .type = NLA_U8 },
        [DEVLINK_ATTR_PARAM_VALUE_CMODE] = { .type = NLA_U8 },
+       [DEVLINK_ATTR_REGION_NAME] = { .type = NLA_NUL_STRING },
 };
 
 static const struct genl_ops devlink_nl_ops[] = {
@@ -3370,6 +3476,14 @@ static const struct genl_ops devlink_nl_ops[] = {
                .flags = GENL_ADMIN_PERM,
                .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
        },
+       {
+               .cmd = DEVLINK_CMD_REGION_GET,
+               .doit = devlink_nl_cmd_region_get_doit,
+               .dumpit = devlink_nl_cmd_region_get_dumpit,
+               .policy = devlink_nl_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
+       },
 };
 
 static struct genl_family devlink_nl_family __ro_after_init = {