Merge tag 'regulator-fix-v6.6-merge-window' of git://git.kernel.org/pub/scm/linux...
[linux-2.6-microblaze.git] / net / devlink / netlink.c
index 7a332eb..fc3e7c0 100644 (file)
@@ -82,6 +82,21 @@ static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
        [DEVLINK_ATTR_REGION_DIRECT] = { .type = NLA_FLAG },
 };
 
+int devlink_nl_msg_reply_and_new(struct sk_buff **msg, struct genl_info *info)
+{
+       int err;
+
+       if (*msg) {
+               err = genlmsg_reply(*msg, info);
+               if (err)
+                       return err;
+       }
+       *msg = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!*msg)
+               return -ENOMEM;
+       return 0;
+}
+
 struct devlink *
 devlink_get_from_attrs_lock(struct net *net, struct nlattr **attrs)
 {
@@ -109,10 +124,9 @@ devlink_get_from_attrs_lock(struct net *net, struct nlattr **attrs)
        return ERR_PTR(-ENODEV);
 }
 
-static int devlink_nl_pre_doit(const struct genl_split_ops *ops,
-                              struct sk_buff *skb, struct genl_info *info)
+static int __devlink_nl_pre_doit(struct sk_buff *skb, struct genl_info *info,
+                                u8 flags)
 {
-       struct devlink_linecard *linecard;
        struct devlink_port *devlink_port;
        struct devlink *devlink;
        int err;
@@ -122,42 +136,17 @@ static int devlink_nl_pre_doit(const struct genl_split_ops *ops,
                return PTR_ERR(devlink);
 
        info->user_ptr[0] = devlink;
-       if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT) {
+       if (flags & DEVLINK_NL_FLAG_NEED_PORT) {
                devlink_port = devlink_port_get_from_info(devlink, info);
                if (IS_ERR(devlink_port)) {
                        err = PTR_ERR(devlink_port);
                        goto unlock;
                }
                info->user_ptr[1] = devlink_port;
-       } else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT) {
+       } else if (flags & DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT) {
                devlink_port = devlink_port_get_from_info(devlink, info);
                if (!IS_ERR(devlink_port))
                        info->user_ptr[1] = devlink_port;
-       } else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_RATE) {
-               struct devlink_rate *devlink_rate;
-
-               devlink_rate = devlink_rate_get_from_info(devlink, info);
-               if (IS_ERR(devlink_rate)) {
-                       err = PTR_ERR(devlink_rate);
-                       goto unlock;
-               }
-               info->user_ptr[1] = devlink_rate;
-       } else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_RATE_NODE) {
-               struct devlink_rate *rate_node;
-
-               rate_node = devlink_rate_node_get_from_info(devlink, info);
-               if (IS_ERR(rate_node)) {
-                       err = PTR_ERR(rate_node);
-                       goto unlock;
-               }
-               info->user_ptr[1] = rate_node;
-       } else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_LINECARD) {
-               linecard = devlink_linecard_get_from_info(devlink, info);
-               if (IS_ERR(linecard)) {
-                       err = PTR_ERR(linecard);
-                       goto unlock;
-               }
-               info->user_ptr[1] = linecard;
        }
        return 0;
 
@@ -167,8 +156,27 @@ unlock:
        return err;
 }
 
-static void devlink_nl_post_doit(const struct genl_split_ops *ops,
-                                struct sk_buff *skb, struct genl_info *info)
+int devlink_nl_pre_doit(const struct genl_split_ops *ops,
+                       struct sk_buff *skb, struct genl_info *info)
+{
+       return __devlink_nl_pre_doit(skb, info, ops->internal_flags);
+}
+
+int devlink_nl_pre_doit_port(const struct genl_split_ops *ops,
+                            struct sk_buff *skb, struct genl_info *info)
+{
+       return __devlink_nl_pre_doit(skb, info, DEVLINK_NL_FLAG_NEED_PORT);
+}
+
+int devlink_nl_pre_doit_port_optional(const struct genl_split_ops *ops,
+                                     struct sk_buff *skb,
+                                     struct genl_info *info)
+{
+       return __devlink_nl_pre_doit(skb, info, DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT);
+}
+
+void devlink_nl_post_doit(const struct genl_split_ops *ops,
+                         struct sk_buff *skb, struct genl_info *info)
 {
        struct devlink *devlink;
 
@@ -177,42 +185,41 @@ static void devlink_nl_post_doit(const struct genl_split_ops *ops,
        devlink_put(devlink);
 }
 
-static const struct devlink_cmd *devl_cmds[] = {
-       [DEVLINK_CMD_GET]               = &devl_cmd_get,
-       [DEVLINK_CMD_PORT_GET]          = &devl_cmd_port_get,
-       [DEVLINK_CMD_SB_GET]            = &devl_cmd_sb_get,
-       [DEVLINK_CMD_SB_POOL_GET]       = &devl_cmd_sb_pool_get,
-       [DEVLINK_CMD_SB_PORT_POOL_GET]  = &devl_cmd_sb_port_pool_get,
-       [DEVLINK_CMD_SB_TC_POOL_BIND_GET] = &devl_cmd_sb_tc_pool_bind_get,
-       [DEVLINK_CMD_PARAM_GET]         = &devl_cmd_param_get,
-       [DEVLINK_CMD_REGION_GET]        = &devl_cmd_region_get,
-       [DEVLINK_CMD_INFO_GET]          = &devl_cmd_info_get,
-       [DEVLINK_CMD_HEALTH_REPORTER_GET] = &devl_cmd_health_reporter_get,
-       [DEVLINK_CMD_TRAP_GET]          = &devl_cmd_trap_get,
-       [DEVLINK_CMD_TRAP_GROUP_GET]    = &devl_cmd_trap_group_get,
-       [DEVLINK_CMD_TRAP_POLICER_GET]  = &devl_cmd_trap_policer_get,
-       [DEVLINK_CMD_RATE_GET]          = &devl_cmd_rate_get,
-       [DEVLINK_CMD_LINECARD_GET]      = &devl_cmd_linecard_get,
-       [DEVLINK_CMD_SELFTESTS_GET]     = &devl_cmd_selftests_get,
-};
+static int devlink_nl_inst_single_dumpit(struct sk_buff *msg,
+                                        struct netlink_callback *cb, int flags,
+                                        devlink_nl_dump_one_func_t *dump_one,
+                                        struct nlattr **attrs)
+{
+       struct devlink *devlink;
+       int err;
+
+       devlink = devlink_get_from_attrs_lock(sock_net(msg->sk), attrs);
+       if (IS_ERR(devlink))
+               return PTR_ERR(devlink);
+       err = dump_one(msg, devlink, cb, flags | NLM_F_DUMP_FILTERED);
+
+       devl_unlock(devlink);
+       devlink_put(devlink);
+
+       if (err != -EMSGSIZE)
+               return err;
+       return msg->len;
+}
 
-int devlink_nl_instance_iter_dumpit(struct sk_buff *msg,
-                                   struct netlink_callback *cb)
+static int devlink_nl_inst_iter_dumpit(struct sk_buff *msg,
+                                      struct netlink_callback *cb, int flags,
+                                      devlink_nl_dump_one_func_t *dump_one)
 {
-       const struct genl_dumpit_info *info = genl_dumpit_info(cb);
        struct devlink_nl_dump_state *state = devlink_dump_state(cb);
-       const struct devlink_cmd *cmd;
        struct devlink *devlink;
        int err = 0;
 
-       cmd = devl_cmds[info->op.cmd];
-
        while ((devlink = devlinks_xa_find_get(sock_net(msg->sk),
                                               &state->instance))) {
                devl_lock(devlink);
 
                if (devl_is_registered(devlink))
-                       err = cmd->dump_one(msg, devlink, cb);
+                       err = dump_one(msg, devlink, cb, flags);
                else
                        err = 0;
 
@@ -233,6 +240,272 @@ int devlink_nl_instance_iter_dumpit(struct sk_buff *msg,
        return msg->len;
 }
 
+int devlink_nl_dumpit(struct sk_buff *msg, struct netlink_callback *cb,
+                     devlink_nl_dump_one_func_t *dump_one)
+{
+       const struct genl_info *info = genl_info_dump(cb);
+       struct nlattr **attrs = info->attrs;
+       int flags = NLM_F_MULTI;
+
+       if (attrs &&
+           (attrs[DEVLINK_ATTR_BUS_NAME] || attrs[DEVLINK_ATTR_DEV_NAME]))
+               return devlink_nl_inst_single_dumpit(msg, cb, flags, dump_one,
+                                                    attrs);
+       else
+               return devlink_nl_inst_iter_dumpit(msg, cb, flags, dump_one);
+}
+
+static const struct genl_small_ops devlink_nl_small_ops[40] = {
+       {
+               .cmd = DEVLINK_CMD_PORT_SET,
+               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+               .doit = devlink_nl_cmd_port_set_doit,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
+       },
+       {
+               .cmd = DEVLINK_CMD_RATE_SET,
+               .doit = devlink_nl_cmd_rate_set_doit,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = DEVLINK_CMD_RATE_NEW,
+               .doit = devlink_nl_cmd_rate_new_doit,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = DEVLINK_CMD_RATE_DEL,
+               .doit = devlink_nl_cmd_rate_del_doit,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = DEVLINK_CMD_PORT_SPLIT,
+               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+               .doit = devlink_nl_cmd_port_split_doit,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
+       },
+       {
+               .cmd = DEVLINK_CMD_PORT_UNSPLIT,
+               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+               .doit = devlink_nl_cmd_port_unsplit_doit,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
+       },
+       {
+               .cmd = DEVLINK_CMD_PORT_NEW,
+               .doit = devlink_nl_cmd_port_new_doit,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = DEVLINK_CMD_PORT_DEL,
+               .doit = devlink_nl_cmd_port_del_doit,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
+       },
+
+       {
+               .cmd = DEVLINK_CMD_LINECARD_SET,
+               .doit = devlink_nl_cmd_linecard_set_doit,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = DEVLINK_CMD_SB_POOL_SET,
+               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+               .doit = devlink_nl_cmd_sb_pool_set_doit,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = DEVLINK_CMD_SB_PORT_POOL_SET,
+               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+               .doit = devlink_nl_cmd_sb_port_pool_set_doit,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
+       },
+       {
+               .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_SET,
+               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+               .doit = devlink_nl_cmd_sb_tc_pool_bind_set_doit,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
+       },
+       {
+               .cmd = DEVLINK_CMD_SB_OCC_SNAPSHOT,
+               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+               .doit = devlink_nl_cmd_sb_occ_snapshot_doit,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = DEVLINK_CMD_SB_OCC_MAX_CLEAR,
+               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+               .doit = devlink_nl_cmd_sb_occ_max_clear_doit,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = DEVLINK_CMD_ESWITCH_GET,
+               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+               .doit = devlink_nl_cmd_eswitch_get_doit,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = DEVLINK_CMD_ESWITCH_SET,
+               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+               .doit = devlink_nl_cmd_eswitch_set_doit,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = DEVLINK_CMD_DPIPE_TABLE_GET,
+               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+               .doit = devlink_nl_cmd_dpipe_table_get,
+               /* can be retrieved by unprivileged users */
+       },
+       {
+               .cmd = DEVLINK_CMD_DPIPE_ENTRIES_GET,
+               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+               .doit = devlink_nl_cmd_dpipe_entries_get,
+               /* can be retrieved by unprivileged users */
+       },
+       {
+               .cmd = DEVLINK_CMD_DPIPE_HEADERS_GET,
+               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+               .doit = devlink_nl_cmd_dpipe_headers_get,
+               /* can be retrieved by unprivileged users */
+       },
+       {
+               .cmd = DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
+               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+               .doit = devlink_nl_cmd_dpipe_table_counters_set,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = DEVLINK_CMD_RESOURCE_SET,
+               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+               .doit = devlink_nl_cmd_resource_set,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = DEVLINK_CMD_RESOURCE_DUMP,
+               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+               .doit = devlink_nl_cmd_resource_dump,
+               /* can be retrieved by unprivileged users */
+       },
+       {
+               .cmd = DEVLINK_CMD_RELOAD,
+               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+               .doit = devlink_nl_cmd_reload,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = DEVLINK_CMD_PARAM_SET,
+               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+               .doit = devlink_nl_cmd_param_set_doit,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = DEVLINK_CMD_PORT_PARAM_GET,
+               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+               .doit = devlink_nl_cmd_port_param_get_doit,
+               .dumpit = devlink_nl_cmd_port_param_get_dumpit,
+               .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
+               /* can be retrieved by unprivileged users */
+       },
+       {
+               .cmd = DEVLINK_CMD_PORT_PARAM_SET,
+               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+               .doit = devlink_nl_cmd_port_param_set_doit,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
+       },
+       {
+               .cmd = DEVLINK_CMD_REGION_NEW,
+               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+               .doit = devlink_nl_cmd_region_new,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = DEVLINK_CMD_REGION_DEL,
+               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+               .doit = devlink_nl_cmd_region_del,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = DEVLINK_CMD_REGION_READ,
+               .validate = GENL_DONT_VALIDATE_STRICT |
+                           GENL_DONT_VALIDATE_DUMP_STRICT,
+               .dumpit = devlink_nl_cmd_region_read_dumpit,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = DEVLINK_CMD_HEALTH_REPORTER_SET,
+               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+               .doit = devlink_nl_cmd_health_reporter_set_doit,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT,
+       },
+       {
+               .cmd = DEVLINK_CMD_HEALTH_REPORTER_RECOVER,
+               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+               .doit = devlink_nl_cmd_health_reporter_recover_doit,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT,
+       },
+       {
+               .cmd = DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE,
+               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+               .doit = devlink_nl_cmd_health_reporter_diagnose_doit,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT,
+       },
+       {
+               .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,
+               .validate = GENL_DONT_VALIDATE_STRICT |
+                           GENL_DONT_VALIDATE_DUMP_STRICT,
+               .dumpit = devlink_nl_cmd_health_reporter_dump_get_dumpit,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR,
+               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+               .doit = devlink_nl_cmd_health_reporter_dump_clear_doit,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT,
+       },
+       {
+               .cmd = DEVLINK_CMD_HEALTH_REPORTER_TEST,
+               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+               .doit = devlink_nl_cmd_health_reporter_test_doit,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT,
+       },
+       {
+               .cmd = DEVLINK_CMD_FLASH_UPDATE,
+               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
+               .doit = devlink_nl_cmd_flash_update,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = DEVLINK_CMD_TRAP_SET,
+               .doit = devlink_nl_cmd_trap_set_doit,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = DEVLINK_CMD_TRAP_GROUP_SET,
+               .doit = devlink_nl_cmd_trap_group_set_doit,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = DEVLINK_CMD_TRAP_POLICER_SET,
+               .doit = devlink_nl_cmd_trap_policer_set_doit,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = DEVLINK_CMD_SELFTESTS_RUN,
+               .doit = devlink_nl_cmd_selftests_run,
+               .flags = GENL_ADMIN_PERM,
+       },
+       /* -- No new ops here! Use split ops going forward! -- */
+};
+
 struct genl_family devlink_nl_family __ro_after_init = {
        .name           = DEVLINK_GENL_NAME,
        .version        = DEVLINK_GENL_VERSION,
@@ -243,8 +516,10 @@ struct genl_family devlink_nl_family __ro_after_init = {
        .pre_doit       = devlink_nl_pre_doit,
        .post_doit      = devlink_nl_post_doit,
        .module         = THIS_MODULE,
-       .small_ops      = devlink_nl_ops,
-       .n_small_ops    = ARRAY_SIZE(devlink_nl_ops),
+       .small_ops      = devlink_nl_small_ops,
+       .n_small_ops    = ARRAY_SIZE(devlink_nl_small_ops),
+       .split_ops      = devlink_nl_ops,
+       .n_split_ops    = ARRAY_SIZE(devlink_nl_ops),
        .resv_start_op  = DEVLINK_CMD_SELFTESTS_RUN + 1,
        .mcgrps         = devlink_nl_mcgrps,
        .n_mcgrps       = ARRAY_SIZE(devlink_nl_mcgrps),