5f57afd31dea54784e317f7c39f45879a1ca6705
[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 int devlink_nl_msg_reply_and_new(struct sk_buff **msg, struct genl_info *info)
86 {
87         int err;
88
89         if (*msg) {
90                 err = genlmsg_reply(*msg, info);
91                 if (err)
92                         return err;
93         }
94         *msg = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
95         if (!*msg)
96                 return -ENOMEM;
97         return 0;
98 }
99
100 struct devlink *
101 devlink_get_from_attrs_lock(struct net *net, struct nlattr **attrs)
102 {
103         struct devlink *devlink;
104         unsigned long index;
105         char *busname;
106         char *devname;
107
108         if (!attrs[DEVLINK_ATTR_BUS_NAME] || !attrs[DEVLINK_ATTR_DEV_NAME])
109                 return ERR_PTR(-EINVAL);
110
111         busname = nla_data(attrs[DEVLINK_ATTR_BUS_NAME]);
112         devname = nla_data(attrs[DEVLINK_ATTR_DEV_NAME]);
113
114         devlinks_xa_for_each_registered_get(net, index, devlink) {
115                 devl_lock(devlink);
116                 if (devl_is_registered(devlink) &&
117                     strcmp(devlink->dev->bus->name, busname) == 0 &&
118                     strcmp(dev_name(devlink->dev), devname) == 0)
119                         return devlink;
120                 devl_unlock(devlink);
121                 devlink_put(devlink);
122         }
123
124         return ERR_PTR(-ENODEV);
125 }
126
127 static int __devlink_nl_pre_doit(struct sk_buff *skb, struct genl_info *info,
128                                  u8 flags)
129 {
130         struct devlink_port *devlink_port;
131         struct devlink *devlink;
132         int err;
133
134         devlink = devlink_get_from_attrs_lock(genl_info_net(info), info->attrs);
135         if (IS_ERR(devlink))
136                 return PTR_ERR(devlink);
137
138         info->user_ptr[0] = devlink;
139         if (flags & DEVLINK_NL_FLAG_NEED_PORT) {
140                 devlink_port = devlink_port_get_from_info(devlink, info);
141                 if (IS_ERR(devlink_port)) {
142                         err = PTR_ERR(devlink_port);
143                         goto unlock;
144                 }
145                 info->user_ptr[1] = devlink_port;
146         } else if (flags & DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT) {
147                 devlink_port = devlink_port_get_from_info(devlink, info);
148                 if (!IS_ERR(devlink_port))
149                         info->user_ptr[1] = devlink_port;
150         }
151         return 0;
152
153 unlock:
154         devl_unlock(devlink);
155         devlink_put(devlink);
156         return err;
157 }
158
159 int devlink_nl_pre_doit(const struct genl_split_ops *ops,
160                         struct sk_buff *skb, struct genl_info *info)
161 {
162         return __devlink_nl_pre_doit(skb, info, ops->internal_flags);
163 }
164
165 int devlink_nl_pre_doit_port(const struct genl_split_ops *ops,
166                              struct sk_buff *skb, struct genl_info *info)
167 {
168         return __devlink_nl_pre_doit(skb, info, DEVLINK_NL_FLAG_NEED_PORT);
169 }
170
171 int devlink_nl_pre_doit_port_optional(const struct genl_split_ops *ops,
172                                       struct sk_buff *skb,
173                                       struct genl_info *info)
174 {
175         return __devlink_nl_pre_doit(skb, info, DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT);
176 }
177
178 void devlink_nl_post_doit(const struct genl_split_ops *ops,
179                           struct sk_buff *skb, struct genl_info *info)
180 {
181         struct devlink *devlink;
182
183         devlink = info->user_ptr[0];
184         devl_unlock(devlink);
185         devlink_put(devlink);
186 }
187
188 static int devlink_nl_inst_single_dumpit(struct sk_buff *msg,
189                                          struct netlink_callback *cb, int flags,
190                                          devlink_nl_dump_one_func_t *dump_one,
191                                          struct nlattr **attrs)
192 {
193         struct devlink *devlink;
194         int err;
195
196         devlink = devlink_get_from_attrs_lock(sock_net(msg->sk), attrs);
197         if (IS_ERR(devlink))
198                 return PTR_ERR(devlink);
199         err = dump_one(msg, devlink, cb, flags | NLM_F_DUMP_FILTERED);
200
201         devl_unlock(devlink);
202         devlink_put(devlink);
203
204         if (err != -EMSGSIZE)
205                 return err;
206         return msg->len;
207 }
208
209 static int devlink_nl_inst_iter_dumpit(struct sk_buff *msg,
210                                        struct netlink_callback *cb, int flags,
211                                        devlink_nl_dump_one_func_t *dump_one)
212 {
213         struct devlink_nl_dump_state *state = devlink_dump_state(cb);
214         struct devlink *devlink;
215         int err = 0;
216
217         while ((devlink = devlinks_xa_find_get(sock_net(msg->sk),
218                                                &state->instance))) {
219                 devl_lock(devlink);
220
221                 if (devl_is_registered(devlink))
222                         err = dump_one(msg, devlink, cb, flags);
223                 else
224                         err = 0;
225
226                 devl_unlock(devlink);
227                 devlink_put(devlink);
228
229                 if (err)
230                         break;
231
232                 state->instance++;
233
234                 /* restart sub-object walk for the next instance */
235                 state->idx = 0;
236         }
237
238         if (err != -EMSGSIZE)
239                 return err;
240         return msg->len;
241 }
242
243 int devlink_nl_dumpit(struct sk_buff *msg, struct netlink_callback *cb,
244                       devlink_nl_dump_one_func_t *dump_one)
245 {
246         const struct genl_info *info = genl_info_dump(cb);
247         struct nlattr **attrs = info->attrs;
248         int flags = NLM_F_MULTI;
249
250         if (attrs &&
251             (attrs[DEVLINK_ATTR_BUS_NAME] || attrs[DEVLINK_ATTR_DEV_NAME]))
252                 return devlink_nl_inst_single_dumpit(msg, cb, flags, dump_one,
253                                                      attrs);
254         else
255                 return devlink_nl_inst_iter_dumpit(msg, cb, flags, dump_one);
256 }
257
258 struct genl_family devlink_nl_family __ro_after_init = {
259         .name           = DEVLINK_GENL_NAME,
260         .version        = DEVLINK_GENL_VERSION,
261         .maxattr        = DEVLINK_ATTR_MAX,
262         .policy         = devlink_nl_policy,
263         .netnsok        = true,
264         .parallel_ops   = true,
265         .pre_doit       = devlink_nl_pre_doit,
266         .post_doit      = devlink_nl_post_doit,
267         .module         = THIS_MODULE,
268         .small_ops      = devlink_nl_small_ops,
269         .n_small_ops    = ARRAY_SIZE(devlink_nl_small_ops),
270         .split_ops      = devlink_nl_ops,
271         .n_split_ops    = ARRAY_SIZE(devlink_nl_ops),
272         .resv_start_op  = DEVLINK_CMD_SELFTESTS_RUN + 1,
273         .mcgrps         = devlink_nl_mcgrps,
274         .n_mcgrps       = ARRAY_SIZE(devlink_nl_mcgrps),
275 };