11666edf5cd288c5ed403f023b177e990d2e297d
[platform/kernel/linux-starfive.git] / net / devlink / netlink.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
4  * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
5  */
6
7 #include <net/genetlink.h>
8 #include <net/sock.h>
9
10 #include "devl_internal.h"
11
12 static const struct genl_multicast_group devlink_nl_mcgrps[] = {
13         [DEVLINK_MCGRP_CONFIG] = { .name = DEVLINK_GENL_MCGRP_CONFIG_NAME },
14 };
15
16 static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
17         [DEVLINK_ATTR_UNSPEC] = { .strict_start_type =
18                 DEVLINK_ATTR_TRAP_POLICER_ID },
19         [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING },
20         [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING },
21         [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32 },
22         [DEVLINK_ATTR_PORT_TYPE] = NLA_POLICY_RANGE(NLA_U16, DEVLINK_PORT_TYPE_AUTO,
23                                                     DEVLINK_PORT_TYPE_IB),
24         [DEVLINK_ATTR_PORT_SPLIT_COUNT] = { .type = NLA_U32 },
25         [DEVLINK_ATTR_SB_INDEX] = { .type = NLA_U32 },
26         [DEVLINK_ATTR_SB_POOL_INDEX] = { .type = NLA_U16 },
27         [DEVLINK_ATTR_SB_POOL_TYPE] = { .type = NLA_U8 },
28         [DEVLINK_ATTR_SB_POOL_SIZE] = { .type = NLA_U32 },
29         [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = { .type = NLA_U8 },
30         [DEVLINK_ATTR_SB_THRESHOLD] = { .type = NLA_U32 },
31         [DEVLINK_ATTR_SB_TC_INDEX] = { .type = NLA_U16 },
32         [DEVLINK_ATTR_ESWITCH_MODE] = NLA_POLICY_RANGE(NLA_U16, DEVLINK_ESWITCH_MODE_LEGACY,
33                                                        DEVLINK_ESWITCH_MODE_SWITCHDEV),
34         [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = { .type = NLA_U8 },
35         [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = { .type = NLA_U8 },
36         [DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .type = NLA_NUL_STRING },
37         [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = { .type = NLA_U8 },
38         [DEVLINK_ATTR_RESOURCE_ID] = { .type = NLA_U64},
39         [DEVLINK_ATTR_RESOURCE_SIZE] = { .type = NLA_U64},
40         [DEVLINK_ATTR_PARAM_NAME] = { .type = NLA_NUL_STRING },
41         [DEVLINK_ATTR_PARAM_TYPE] = { .type = NLA_U8 },
42         [DEVLINK_ATTR_PARAM_VALUE_CMODE] = { .type = NLA_U8 },
43         [DEVLINK_ATTR_REGION_NAME] = { .type = NLA_NUL_STRING },
44         [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = { .type = NLA_U32 },
45         [DEVLINK_ATTR_REGION_CHUNK_ADDR] = { .type = NLA_U64 },
46         [DEVLINK_ATTR_REGION_CHUNK_LEN] = { .type = NLA_U64 },
47         [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .type = NLA_NUL_STRING },
48         [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = { .type = NLA_U64 },
49         [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER] = { .type = NLA_U8 },
50         [DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME] = { .type = NLA_NUL_STRING },
51         [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT] = { .type = NLA_NUL_STRING },
52         [DEVLINK_ATTR_FLASH_UPDATE_OVERWRITE_MASK] =
53                 NLA_POLICY_BITFIELD32(DEVLINK_SUPPORTED_FLASH_OVERWRITE_SECTIONS),
54         [DEVLINK_ATTR_TRAP_NAME] = { .type = NLA_NUL_STRING },
55         [DEVLINK_ATTR_TRAP_ACTION] = { .type = NLA_U8 },
56         [DEVLINK_ATTR_TRAP_GROUP_NAME] = { .type = NLA_NUL_STRING },
57         [DEVLINK_ATTR_NETNS_PID] = { .type = NLA_U32 },
58         [DEVLINK_ATTR_NETNS_FD] = { .type = NLA_U32 },
59         [DEVLINK_ATTR_NETNS_ID] = { .type = NLA_U32 },
60         [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP] = { .type = NLA_U8 },
61         [DEVLINK_ATTR_TRAP_POLICER_ID] = { .type = NLA_U32 },
62         [DEVLINK_ATTR_TRAP_POLICER_RATE] = { .type = NLA_U64 },
63         [DEVLINK_ATTR_TRAP_POLICER_BURST] = { .type = NLA_U64 },
64         [DEVLINK_ATTR_PORT_FUNCTION] = { .type = NLA_NESTED },
65         [DEVLINK_ATTR_RELOAD_ACTION] = NLA_POLICY_RANGE(NLA_U8, DEVLINK_RELOAD_ACTION_DRIVER_REINIT,
66                                                         DEVLINK_RELOAD_ACTION_MAX),
67         [DEVLINK_ATTR_RELOAD_LIMITS] = NLA_POLICY_BITFIELD32(DEVLINK_RELOAD_LIMITS_VALID_MASK),
68         [DEVLINK_ATTR_PORT_FLAVOUR] = { .type = NLA_U16 },
69         [DEVLINK_ATTR_PORT_PCI_PF_NUMBER] = { .type = NLA_U16 },
70         [DEVLINK_ATTR_PORT_PCI_SF_NUMBER] = { .type = NLA_U32 },
71         [DEVLINK_ATTR_PORT_CONTROLLER_NUMBER] = { .type = NLA_U32 },
72         [DEVLINK_ATTR_RATE_TYPE] = { .type = NLA_U16 },
73         [DEVLINK_ATTR_RATE_TX_SHARE] = { .type = NLA_U64 },
74         [DEVLINK_ATTR_RATE_TX_MAX] = { .type = NLA_U64 },
75         [DEVLINK_ATTR_RATE_NODE_NAME] = { .type = NLA_NUL_STRING },
76         [DEVLINK_ATTR_RATE_PARENT_NODE_NAME] = { .type = NLA_NUL_STRING },
77         [DEVLINK_ATTR_LINECARD_INDEX] = { .type = NLA_U32 },
78         [DEVLINK_ATTR_LINECARD_TYPE] = { .type = NLA_NUL_STRING },
79         [DEVLINK_ATTR_SELFTESTS] = { .type = NLA_NESTED },
80         [DEVLINK_ATTR_RATE_TX_PRIORITY] = { .type = NLA_U32 },
81         [DEVLINK_ATTR_RATE_TX_WEIGHT] = { .type = NLA_U32 },
82         [DEVLINK_ATTR_REGION_DIRECT] = { .type = NLA_FLAG },
83 };
84
85 struct devlink *
86 devlink_get_from_attrs_lock(struct net *net, struct nlattr **attrs)
87 {
88         struct devlink *devlink;
89         unsigned long index;
90         char *busname;
91         char *devname;
92
93         if (!attrs[DEVLINK_ATTR_BUS_NAME] || !attrs[DEVLINK_ATTR_DEV_NAME])
94                 return ERR_PTR(-EINVAL);
95
96         busname = nla_data(attrs[DEVLINK_ATTR_BUS_NAME]);
97         devname = nla_data(attrs[DEVLINK_ATTR_DEV_NAME]);
98
99         devlinks_xa_for_each_registered_get(net, index, devlink) {
100                 devl_lock(devlink);
101                 if (devl_is_registered(devlink) &&
102                     strcmp(devlink->dev->bus->name, busname) == 0 &&
103                     strcmp(dev_name(devlink->dev), devname) == 0)
104                         return devlink;
105                 devl_unlock(devlink);
106                 devlink_put(devlink);
107         }
108
109         return ERR_PTR(-ENODEV);
110 }
111
112 static int devlink_nl_pre_doit(const struct genl_split_ops *ops,
113                                struct sk_buff *skb, struct genl_info *info)
114 {
115         struct devlink_linecard *linecard;
116         struct devlink_port *devlink_port;
117         struct devlink *devlink;
118         int err;
119
120         devlink = devlink_get_from_attrs_lock(genl_info_net(info), info->attrs);
121         if (IS_ERR(devlink))
122                 return PTR_ERR(devlink);
123
124         info->user_ptr[0] = devlink;
125         if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT) {
126                 devlink_port = devlink_port_get_from_info(devlink, info);
127                 if (IS_ERR(devlink_port)) {
128                         err = PTR_ERR(devlink_port);
129                         goto unlock;
130                 }
131                 info->user_ptr[1] = devlink_port;
132         } else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT) {
133                 devlink_port = devlink_port_get_from_info(devlink, info);
134                 if (!IS_ERR(devlink_port))
135                         info->user_ptr[1] = devlink_port;
136         } else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_RATE) {
137                 struct devlink_rate *devlink_rate;
138
139                 devlink_rate = devlink_rate_get_from_info(devlink, info);
140                 if (IS_ERR(devlink_rate)) {
141                         err = PTR_ERR(devlink_rate);
142                         goto unlock;
143                 }
144                 info->user_ptr[1] = devlink_rate;
145         } else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_RATE_NODE) {
146                 struct devlink_rate *rate_node;
147
148                 rate_node = devlink_rate_node_get_from_info(devlink, info);
149                 if (IS_ERR(rate_node)) {
150                         err = PTR_ERR(rate_node);
151                         goto unlock;
152                 }
153                 info->user_ptr[1] = rate_node;
154         } else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_LINECARD) {
155                 linecard = devlink_linecard_get_from_info(devlink, info);
156                 if (IS_ERR(linecard)) {
157                         err = PTR_ERR(linecard);
158                         goto unlock;
159                 }
160                 info->user_ptr[1] = linecard;
161         }
162         return 0;
163
164 unlock:
165         devl_unlock(devlink);
166         devlink_put(devlink);
167         return err;
168 }
169
170 static void devlink_nl_post_doit(const struct genl_split_ops *ops,
171                                  struct sk_buff *skb, struct genl_info *info)
172 {
173         struct devlink *devlink;
174
175         devlink = info->user_ptr[0];
176         devl_unlock(devlink);
177         devlink_put(devlink);
178 }
179
180 static const struct devlink_gen_cmd *devl_gen_cmds[] = {
181         [DEVLINK_CMD_GET]               = &devl_gen_inst,
182         [DEVLINK_CMD_PORT_GET]          = &devl_gen_port,
183         [DEVLINK_CMD_SB_GET]            = &devl_gen_sb,
184         [DEVLINK_CMD_SB_POOL_GET]       = &devl_gen_sb_pool,
185         [DEVLINK_CMD_SB_PORT_POOL_GET]  = &devl_gen_sb_port_pool,
186         [DEVLINK_CMD_SB_TC_POOL_BIND_GET] = &devl_gen_sb_tc_pool_bind,
187         [DEVLINK_CMD_PARAM_GET]         = &devl_gen_param,
188         [DEVLINK_CMD_REGION_GET]        = &devl_gen_region,
189         [DEVLINK_CMD_INFO_GET]          = &devl_gen_info,
190         [DEVLINK_CMD_HEALTH_REPORTER_GET] = &devl_gen_health_reporter,
191         [DEVLINK_CMD_RATE_GET]          = &devl_gen_rate_get,
192         [DEVLINK_CMD_TRAP_GET]          = &devl_gen_trap,
193         [DEVLINK_CMD_TRAP_GROUP_GET]    = &devl_gen_trap_group,
194         [DEVLINK_CMD_TRAP_POLICER_GET]  = &devl_gen_trap_policer,
195         [DEVLINK_CMD_LINECARD_GET]      = &devl_gen_linecard,
196         [DEVLINK_CMD_SELFTESTS_GET]     = &devl_gen_selftests,
197 };
198
199 int devlink_nl_instance_iter_dumpit(struct sk_buff *msg,
200                                     struct netlink_callback *cb)
201 {
202         const struct genl_dumpit_info *info = genl_dumpit_info(cb);
203         struct devlink_nl_dump_state *state = devlink_dump_state(cb);
204         const struct devlink_gen_cmd *cmd;
205         struct devlink *devlink;
206         int err = 0;
207
208         cmd = devl_gen_cmds[info->op.cmd];
209
210         while ((devlink = devlinks_xa_find_get(sock_net(msg->sk),
211                                                &state->instance))) {
212                 devl_lock(devlink);
213
214                 if (devl_is_registered(devlink))
215                         err = cmd->dump_one(msg, devlink, cb);
216                 else
217                         err = 0;
218
219                 devl_unlock(devlink);
220                 devlink_put(devlink);
221
222                 if (err)
223                         break;
224
225                 state->instance++;
226
227                 /* restart sub-object walk for the next instance */
228                 state->idx = 0;
229         }
230
231         if (err != -EMSGSIZE)
232                 return err;
233         return msg->len;
234 }
235
236 struct genl_family devlink_nl_family __ro_after_init = {
237         .name           = DEVLINK_GENL_NAME,
238         .version        = DEVLINK_GENL_VERSION,
239         .maxattr        = DEVLINK_ATTR_MAX,
240         .policy         = devlink_nl_policy,
241         .netnsok        = true,
242         .parallel_ops   = true,
243         .pre_doit       = devlink_nl_pre_doit,
244         .post_doit      = devlink_nl_post_doit,
245         .module         = THIS_MODULE,
246         .small_ops      = devlink_nl_ops,
247         .n_small_ops    = ARRAY_SIZE(devlink_nl_ops),
248         .resv_start_op  = DEVLINK_CMD_SELFTESTS_RUN + 1,
249         .mcgrps         = devlink_nl_mcgrps,
250         .n_mcgrps       = ARRAY_SIZE(devlink_nl_mcgrps),
251 };