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