]> git.ipfire.org Git - thirdparty/linux.git/blame - net/devlink/netlink.c
fs: indicate request originates from old mount API
[thirdparty/linux.git] / net / devlink / netlink.c
CommitLineData
623cd13b
JK
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>
07f3af66 8#include <net/sock.h>
623cd13b
JK
9
10#include "devl_internal.h"
11
12static const struct genl_multicast_group devlink_nl_mcgrps[] = {
13 [DEVLINK_MCGRP_CONFIG] = { .name = DEVLINK_GENL_MCGRP_CONFIG_NAME },
14};
15
af1f1400 16int devlink_nl_put_nested_handle(struct sk_buff *msg, struct net *net,
1c2197c4 17 struct devlink *devlink, int attrtype)
af1f1400
JP
18{
19 struct nlattr *nested_attr;
c503bc7d 20 struct net *devl_net;
af1f1400 21
1c2197c4 22 nested_attr = nla_nest_start(msg, attrtype);
af1f1400
JP
23 if (!nested_attr)
24 return -EMSGSIZE;
25 if (devlink_nl_put_handle(msg, devlink))
26 goto nla_put_failure;
af1f1400 27
c503bc7d
JP
28 rcu_read_lock();
29 devl_net = read_pnet_rcu(&devlink->_net);
30 if (!net_eq(net, devl_net)) {
31 int id = peernet2id_alloc(net, devl_net, GFP_ATOMIC);
32
33 rcu_read_unlock();
af1f1400
JP
34 if (nla_put_s32(msg, DEVLINK_ATTR_NETNS_ID, id))
35 return -EMSGSIZE;
c503bc7d
JP
36 } else {
37 rcu_read_unlock();
af1f1400
JP
38 }
39
40 nla_nest_end(msg, nested_attr);
41 return 0;
42
43nla_put_failure:
44 nla_nest_cancel(msg, nested_attr);
45 return -EMSGSIZE;
46}
47
2475ed15
JP
48int devlink_nl_msg_reply_and_new(struct sk_buff **msg, struct genl_info *info)
49{
50 int err;
51
52 if (*msg) {
53 err = genlmsg_reply(*msg, info);
54 if (err)
55 return err;
56 }
57 *msg = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
58 if (!*msg)
59 return -ENOMEM;
60 return 0;
61}
62
870c7ad4
JK
63struct devlink *
64devlink_get_from_attrs_lock(struct net *net, struct nlattr **attrs)
623cd13b
JK
65{
66 struct devlink *devlink;
67 unsigned long index;
68 char *busname;
69 char *devname;
70
71 if (!attrs[DEVLINK_ATTR_BUS_NAME] || !attrs[DEVLINK_ATTR_DEV_NAME])
72 return ERR_PTR(-EINVAL);
73
74 busname = nla_data(attrs[DEVLINK_ATTR_BUS_NAME]);
75 devname = nla_data(attrs[DEVLINK_ATTR_DEV_NAME]);
76
77 devlinks_xa_for_each_registered_get(net, index, devlink) {
870c7ad4 78 devl_lock(devlink);
ed539ba6
JK
79 if (devl_is_registered(devlink) &&
80 strcmp(devlink->dev->bus->name, busname) == 0 &&
623cd13b
JK
81 strcmp(dev_name(devlink->dev), devname) == 0)
82 return devlink;
870c7ad4 83 devl_unlock(devlink);
623cd13b
JK
84 devlink_put(devlink);
85 }
86
87 return ERR_PTR(-ENODEV);
88}
89
ee6d78ac
JP
90static int __devlink_nl_pre_doit(struct sk_buff *skb, struct genl_info *info,
91 u8 flags)
623cd13b 92{
623cd13b
JK
93 struct devlink_port *devlink_port;
94 struct devlink *devlink;
95 int err;
96
870c7ad4 97 devlink = devlink_get_from_attrs_lock(genl_info_net(info), info->attrs);
623cd13b
JK
98 if (IS_ERR(devlink))
99 return PTR_ERR(devlink);
870c7ad4 100
623cd13b 101 info->user_ptr[0] = devlink;
ee6d78ac 102 if (flags & DEVLINK_NL_FLAG_NEED_PORT) {
623cd13b
JK
103 devlink_port = devlink_port_get_from_info(devlink, info);
104 if (IS_ERR(devlink_port)) {
105 err = PTR_ERR(devlink_port);
106 goto unlock;
107 }
108 info->user_ptr[1] = devlink_port;
ee6d78ac 109 } else if (flags & DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT) {
623cd13b
JK
110 devlink_port = devlink_port_get_from_info(devlink, info);
111 if (!IS_ERR(devlink_port))
112 info->user_ptr[1] = devlink_port;
623cd13b
JK
113 }
114 return 0;
115
116unlock:
117 devl_unlock(devlink);
118 devlink_put(devlink);
119 return err;
120}
121
ee6d78ac
JP
122int devlink_nl_pre_doit(const struct genl_split_ops *ops,
123 struct sk_buff *skb, struct genl_info *info)
124{
cebe7306 125 return __devlink_nl_pre_doit(skb, info, 0);
ee6d78ac
JP
126}
127
128int devlink_nl_pre_doit_port(const struct genl_split_ops *ops,
129 struct sk_buff *skb, struct genl_info *info)
130{
131 return __devlink_nl_pre_doit(skb, info, DEVLINK_NL_FLAG_NEED_PORT);
132}
133
134int devlink_nl_pre_doit_port_optional(const struct genl_split_ops *ops,
135 struct sk_buff *skb,
136 struct genl_info *info)
137{
138 return __devlink_nl_pre_doit(skb, info, DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT);
139}
140
8300dce5
JP
141void devlink_nl_post_doit(const struct genl_split_ops *ops,
142 struct sk_buff *skb, struct genl_info *info)
623cd13b 143{
623cd13b
JK
144 struct devlink *devlink;
145
146 devlink = info->user_ptr[0];
623cd13b
JK
147 devl_unlock(devlink);
148 devlink_put(devlink);
149}
150
4a1b5aa8
JP
151static int devlink_nl_inst_single_dumpit(struct sk_buff *msg,
152 struct netlink_callback *cb, int flags,
153 devlink_nl_dump_one_func_t *dump_one,
154 struct nlattr **attrs)
155{
156 struct devlink *devlink;
157 int err;
158
159 devlink = devlink_get_from_attrs_lock(sock_net(msg->sk), attrs);
160 if (IS_ERR(devlink))
161 return PTR_ERR(devlink);
162 err = dump_one(msg, devlink, cb, flags | NLM_F_DUMP_FILTERED);
163
164 devl_unlock(devlink);
165 devlink_put(devlink);
166
167 if (err != -EMSGSIZE)
168 return err;
169 return msg->len;
170}
171
172static int devlink_nl_inst_iter_dumpit(struct sk_buff *msg,
173 struct netlink_callback *cb, int flags,
174 devlink_nl_dump_one_func_t *dump_one)
07f3af66 175{
07f3af66 176 struct devlink_nl_dump_state *state = devlink_dump_state(cb);
07f3af66
JK
177 struct devlink *devlink;
178 int err = 0;
179
543753d9
JP
180 while ((devlink = devlinks_xa_find_get(sock_net(msg->sk),
181 &state->instance))) {
07f3af66 182 devl_lock(devlink);
ed539ba6
JK
183
184 if (devl_is_registered(devlink))
4a1b5aa8 185 err = dump_one(msg, devlink, cb, flags);
ed539ba6
JK
186 else
187 err = 0;
188
07f3af66
JK
189 devl_unlock(devlink);
190 devlink_put(devlink);
191
192 if (err)
193 break;
194
543753d9
JP
195 state->instance++;
196
07f3af66
JK
197 /* restart sub-object walk for the next instance */
198 state->idx = 0;
199 }
200
201 if (err != -EMSGSIZE)
202 return err;
203 return msg->len;
204}
205
4a1b5aa8
JP
206int devlink_nl_dumpit(struct sk_buff *msg, struct netlink_callback *cb,
207 devlink_nl_dump_one_func_t *dump_one)
208{
7288dd2f 209 const struct genl_info *info = genl_info_dump(cb);
4a1b5aa8
JP
210 struct nlattr **attrs = info->attrs;
211 int flags = NLM_F_MULTI;
212
213 if (attrs &&
214 (attrs[DEVLINK_ATTR_BUS_NAME] || attrs[DEVLINK_ATTR_DEV_NAME]))
215 return devlink_nl_inst_single_dumpit(msg, cb, flags, dump_one,
216 attrs);
217 else
218 return devlink_nl_inst_iter_dumpit(msg, cb, flags, dump_one);
219}
220
623cd13b
JK
221struct genl_family devlink_nl_family __ro_after_init = {
222 .name = DEVLINK_GENL_NAME,
223 .version = DEVLINK_GENL_VERSION,
623cd13b
JK
224 .netnsok = true,
225 .parallel_ops = true,
623cd13b 226 .module = THIS_MODULE,
6e067d0c
JP
227 .split_ops = devlink_nl_ops,
228 .n_split_ops = ARRAY_SIZE(devlink_nl_ops),
623cd13b
JK
229 .resv_start_op = DEVLINK_CMD_SELFTESTS_RUN + 1,
230 .mcgrps = devlink_nl_mcgrps,
231 .n_mcgrps = ARRAY_SIZE(devlink_nl_mcgrps),
232};