xref: /linux/net/devlink/netlink.c (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
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 #define DEVLINK_NL_FLAG_OPTIONAL_PARENT_DEV	BIT(3)
16 
17 static const struct genl_multicast_group devlink_nl_mcgrps[] = {
18 	[DEVLINK_MCGRP_CONFIG] = { .name = DEVLINK_GENL_MCGRP_CONFIG_NAME },
19 };
20 
21 struct devlink_nl_sock_priv {
22 	struct devlink_obj_desc __rcu *flt;
23 	spinlock_t flt_lock; /* Protects flt. */
24 };
25 
devlink_nl_sock_priv_init(void * priv)26 static void devlink_nl_sock_priv_init(void *priv)
27 {
28 	struct devlink_nl_sock_priv *sk_priv = priv;
29 
30 	spin_lock_init(&sk_priv->flt_lock);
31 }
32 
devlink_nl_sock_priv_destroy(void * priv)33 static void devlink_nl_sock_priv_destroy(void *priv)
34 {
35 	struct devlink_nl_sock_priv *sk_priv = priv;
36 	struct devlink_obj_desc *flt;
37 
38 	flt = rcu_dereference_protected(sk_priv->flt, true);
39 	kfree_rcu(flt, rcu);
40 }
41 
devlink_nl_notify_filter_set_doit(struct sk_buff * skb,struct genl_info * info)42 int devlink_nl_notify_filter_set_doit(struct sk_buff *skb,
43 				      struct genl_info *info)
44 {
45 	struct devlink_nl_sock_priv *sk_priv;
46 	struct nlattr **attrs = info->attrs;
47 	struct devlink_obj_desc *flt;
48 	size_t data_offset = 0;
49 	size_t data_size = 0;
50 	char *pos;
51 
52 	if (attrs[DEVLINK_ATTR_BUS_NAME])
53 		data_size = size_add(data_size,
54 				     nla_len(attrs[DEVLINK_ATTR_BUS_NAME]) + 1);
55 	if (attrs[DEVLINK_ATTR_DEV_NAME])
56 		data_size = size_add(data_size,
57 				     nla_len(attrs[DEVLINK_ATTR_DEV_NAME]) + 1);
58 
59 	flt = kzalloc(size_add(sizeof(*flt), data_size), GFP_KERNEL);
60 	if (!flt)
61 		return -ENOMEM;
62 
63 	pos = (char *) flt->data;
64 	if (attrs[DEVLINK_ATTR_BUS_NAME]) {
65 		data_offset += nla_strscpy(pos,
66 					   attrs[DEVLINK_ATTR_BUS_NAME],
67 					   data_size) + 1;
68 		flt->bus_name = pos;
69 		pos += data_offset;
70 	}
71 	if (attrs[DEVLINK_ATTR_DEV_NAME]) {
72 		nla_strscpy(pos, attrs[DEVLINK_ATTR_DEV_NAME],
73 			    data_size - data_offset);
74 		flt->dev_name = pos;
75 	}
76 
77 	if (attrs[DEVLINK_ATTR_INDEX]) {
78 		flt->devlink_index = nla_get_uint(attrs[DEVLINK_ATTR_INDEX]);
79 		flt->devlink_index_valid = true;
80 	}
81 
82 	if (attrs[DEVLINK_ATTR_PORT_INDEX]) {
83 		flt->port_index = nla_get_u32(attrs[DEVLINK_ATTR_PORT_INDEX]);
84 		flt->port_index_valid = true;
85 	}
86 
87 	/* Don't attach empty filter. */
88 	if (!flt->bus_name && !flt->dev_name &&
89 	    !flt->devlink_index_valid && !flt->port_index_valid) {
90 		kfree(flt);
91 		flt = NULL;
92 	}
93 
94 	sk_priv = genl_sk_priv_get(&devlink_nl_family, NETLINK_CB(skb).sk);
95 	if (IS_ERR(sk_priv)) {
96 		kfree(flt);
97 		return PTR_ERR(sk_priv);
98 	}
99 	spin_lock(&sk_priv->flt_lock);
100 	flt = rcu_replace_pointer(sk_priv->flt, flt,
101 				  lockdep_is_held(&sk_priv->flt_lock));
102 	spin_unlock(&sk_priv->flt_lock);
103 	kfree_rcu(flt, rcu);
104 	return 0;
105 }
106 
devlink_obj_desc_match(const struct devlink_obj_desc * desc,const struct devlink_obj_desc * flt)107 static bool devlink_obj_desc_match(const struct devlink_obj_desc *desc,
108 				   const struct devlink_obj_desc *flt)
109 {
110 	if (desc->devlink_index_valid && flt->devlink_index_valid &&
111 	    desc->devlink_index != flt->devlink_index)
112 		return false;
113 	if (desc->bus_name && flt->bus_name &&
114 	    strcmp(desc->bus_name, flt->bus_name))
115 		return false;
116 	if (desc->dev_name && flt->dev_name &&
117 	    strcmp(desc->dev_name, flt->dev_name))
118 		return false;
119 	if (desc->port_index_valid && flt->port_index_valid &&
120 	    desc->port_index != flt->port_index)
121 		return false;
122 	return true;
123 }
124 
devlink_nl_notify_filter(struct sock * dsk,struct sk_buff * skb,void * data)125 int devlink_nl_notify_filter(struct sock *dsk, struct sk_buff *skb, void *data)
126 {
127 	struct devlink_obj_desc *desc = data;
128 	struct devlink_nl_sock_priv *sk_priv;
129 	struct devlink_obj_desc *flt;
130 	int ret = 0;
131 
132 	rcu_read_lock();
133 	sk_priv = __genl_sk_priv_get(&devlink_nl_family, dsk);
134 	if (!IS_ERR_OR_NULL(sk_priv)) {
135 		flt = rcu_dereference(sk_priv->flt);
136 		if (flt)
137 			ret = !devlink_obj_desc_match(desc, flt);
138 	}
139 	rcu_read_unlock();
140 	return ret;
141 }
142 
devlink_nl_put_nested_handle(struct sk_buff * msg,struct net * net,struct devlink * devlink,int attrtype)143 int devlink_nl_put_nested_handle(struct sk_buff *msg, struct net *net,
144 				 struct devlink *devlink, int attrtype)
145 {
146 	struct nlattr *nested_attr;
147 	struct net *devl_net;
148 
149 	nested_attr = nla_nest_start(msg, attrtype);
150 	if (!nested_attr)
151 		return -EMSGSIZE;
152 	if (devlink_nl_put_handle(msg, devlink))
153 		goto nla_put_failure;
154 
155 	rcu_read_lock();
156 	devl_net = read_pnet_rcu(&devlink->_net);
157 	if (!net_eq(net, devl_net)) {
158 		int id = peernet2id_alloc(net, devl_net, GFP_ATOMIC);
159 
160 		rcu_read_unlock();
161 		if (nla_put_s32(msg, DEVLINK_ATTR_NETNS_ID, id))
162 			return -EMSGSIZE;
163 	} else {
164 		rcu_read_unlock();
165 	}
166 
167 	nla_nest_end(msg, nested_attr);
168 	return 0;
169 
170 nla_put_failure:
171 	nla_nest_cancel(msg, nested_attr);
172 	return -EMSGSIZE;
173 }
174 
devlink_nl_msg_reply_and_new(struct sk_buff ** msg,struct genl_info * info)175 int devlink_nl_msg_reply_and_new(struct sk_buff **msg, struct genl_info *info)
176 {
177 	int err;
178 
179 	if (*msg) {
180 		err = genlmsg_reply(*msg, info);
181 		if (err)
182 			return err;
183 	}
184 	*msg = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
185 	if (!*msg)
186 		return -ENOMEM;
187 	return 0;
188 }
189 
190 struct devlink *
devlink_get_from_attrs_lock(struct net * net,struct nlattr ** attrs,bool dev_lock)191 devlink_get_from_attrs_lock(struct net *net, struct nlattr **attrs,
192 			    bool dev_lock)
193 {
194 	struct devlink *devlink;
195 	unsigned long index;
196 	char *busname;
197 	char *devname;
198 
199 	if (attrs[DEVLINK_ATTR_INDEX]) {
200 		if (attrs[DEVLINK_ATTR_BUS_NAME] ||
201 		    attrs[DEVLINK_ATTR_DEV_NAME])
202 			return ERR_PTR(-EINVAL);
203 		index = nla_get_u32(attrs[DEVLINK_ATTR_INDEX]);
204 		devlink = devlinks_xa_lookup_get(net, index);
205 		if (!devlink)
206 			return ERR_PTR(-ENODEV);
207 		goto found;
208 	}
209 
210 	if (!attrs[DEVLINK_ATTR_BUS_NAME] || !attrs[DEVLINK_ATTR_DEV_NAME])
211 		return ERR_PTR(-EINVAL);
212 
213 	busname = nla_data(attrs[DEVLINK_ATTR_BUS_NAME]);
214 	devname = nla_data(attrs[DEVLINK_ATTR_DEV_NAME]);
215 
216 	if (!strcmp(busname, DEVLINK_INDEX_BUS_NAME)) {
217 		if (kstrtoul(devname, 10, &index))
218 			return ERR_PTR(-ENODEV);
219 		devlink = devlinks_xa_lookup_get(net, index);
220 		if (!devlink)
221 			return ERR_PTR(-ENODEV);
222 		goto found;
223 	}
224 
225 	devlinks_xa_for_each_registered_get(net, index, devlink) {
226 		if (strcmp(devlink_bus_name(devlink), busname) == 0 &&
227 		    strcmp(devlink_dev_name(devlink), devname) == 0)
228 			goto found;
229 		devlink_put(devlink);
230 	}
231 
232 	return ERR_PTR(-ENODEV);
233 
234 found:
235 	devl_dev_lock(devlink, dev_lock);
236 	if (devl_is_registered(devlink))
237 		return devlink;
238 	devl_dev_unlock(devlink, dev_lock);
239 	devlink_put(devlink);
240 	return ERR_PTR(-ENODEV);
241 }
242 
243 struct devlink *
devlink_get_parent_from_attrs_lock(struct net * net,struct nlattr ** attrs)244 devlink_get_parent_from_attrs_lock(struct net *net, struct nlattr **attrs)
245 {
246 	unsigned int maxtype = ARRAY_SIZE(devlink_dl_parent_dev_nl_policy) - 1;
247 	struct devlink *devlink;
248 	struct nlattr **tb;
249 	int err;
250 
251 	if (!attrs[DEVLINK_ATTR_PARENT_DEV])
252 		return ERR_PTR(-EINVAL);
253 
254 	tb = kcalloc(maxtype + 1, sizeof(*tb), GFP_KERNEL);
255 	if (!tb)
256 		return ERR_PTR(-ENOMEM);
257 
258 	err = nla_parse_nested(tb, maxtype, attrs[DEVLINK_ATTR_PARENT_DEV],
259 			       devlink_dl_parent_dev_nl_policy, NULL);
260 	if (err)
261 		goto out;
262 
263 	devlink = devlink_get_from_attrs_lock(net, tb, false);
264 	kfree(tb);
265 	return devlink;
266 out:
267 	kfree(tb);
268 	return ERR_PTR(err);
269 }
270 
__devlink_nl_pre_doit(struct sk_buff * skb,struct genl_info * info,u8 flags)271 static int __devlink_nl_pre_doit(struct sk_buff *skb, struct genl_info *info,
272 				 u8 flags)
273 {
274 	bool parent_dev = flags & DEVLINK_NL_FLAG_OPTIONAL_PARENT_DEV;
275 	bool dev_lock = flags & DEVLINK_NL_FLAG_NEED_DEV_LOCK;
276 	struct devlink *devlink, *parent_devlink = NULL;
277 	struct net *net = genl_info_net(info);
278 	struct nlattr **attrs = info->attrs;
279 	struct devlink_port *devlink_port;
280 	int err;
281 
282 	if (parent_dev && attrs[DEVLINK_ATTR_PARENT_DEV]) {
283 		parent_devlink = devlink_get_parent_from_attrs_lock(net, attrs);
284 		if (IS_ERR(parent_devlink))
285 			return PTR_ERR(parent_devlink);
286 		devlink_nl_ctx(info)->parent_devlink = parent_devlink;
287 		/* Drop the parent devlink lock but don't release the reference.
288 		 * This will keep it alive until the end of the request.
289 		 */
290 		devl_unlock(parent_devlink);
291 	}
292 
293 	devlink = devlink_get_from_attrs_lock(net, attrs, dev_lock);
294 	if (IS_ERR(devlink)) {
295 		err = PTR_ERR(devlink);
296 		goto parent_put;
297 	}
298 	devlink_nl_ctx(info)->devlink = devlink;
299 	if (flags & DEVLINK_NL_FLAG_NEED_PORT) {
300 		devlink_port = devlink_port_get_from_info(devlink, info);
301 		if (IS_ERR(devlink_port)) {
302 			err = PTR_ERR(devlink_port);
303 			goto unlock;
304 		}
305 		devlink_nl_ctx(info)->devlink_port = devlink_port;
306 	} else if (flags & DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT) {
307 		devlink_port = devlink_port_get_from_info(devlink, info);
308 		if (!IS_ERR(devlink_port))
309 			devlink_nl_ctx(info)->devlink_port = devlink_port;
310 	}
311 	return 0;
312 
313 unlock:
314 	devl_dev_unlock(devlink, dev_lock);
315 	devlink_put(devlink);
316 parent_put:
317 	if (parent_dev && parent_devlink)
318 		devlink_put(parent_devlink);
319 	return err;
320 }
321 
devlink_nl_pre_doit(const struct genl_split_ops * ops,struct sk_buff * skb,struct genl_info * info)322 int devlink_nl_pre_doit(const struct genl_split_ops *ops,
323 			struct sk_buff *skb, struct genl_info *info)
324 {
325 	return __devlink_nl_pre_doit(skb, info, 0);
326 }
327 
devlink_nl_pre_doit_port(const struct genl_split_ops * ops,struct sk_buff * skb,struct genl_info * info)328 int devlink_nl_pre_doit_port(const struct genl_split_ops *ops,
329 			     struct sk_buff *skb, struct genl_info *info)
330 {
331 	return __devlink_nl_pre_doit(skb, info, DEVLINK_NL_FLAG_NEED_PORT);
332 }
333 
devlink_nl_pre_doit_dev_lock(const struct genl_split_ops * ops,struct sk_buff * skb,struct genl_info * info)334 int devlink_nl_pre_doit_dev_lock(const struct genl_split_ops *ops,
335 				 struct sk_buff *skb, struct genl_info *info)
336 {
337 	return __devlink_nl_pre_doit(skb, info, DEVLINK_NL_FLAG_NEED_DEV_LOCK);
338 }
339 
devlink_nl_pre_doit_port_optional(const struct genl_split_ops * ops,struct sk_buff * skb,struct genl_info * info)340 int devlink_nl_pre_doit_port_optional(const struct genl_split_ops *ops,
341 				      struct sk_buff *skb,
342 				      struct genl_info *info)
343 {
344 	return __devlink_nl_pre_doit(skb, info, DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT);
345 }
346 
devlink_nl_pre_doit_parent_dev_optional(const struct genl_split_ops * ops,struct sk_buff * skb,struct genl_info * info)347 int devlink_nl_pre_doit_parent_dev_optional(const struct genl_split_ops *ops,
348 					    struct sk_buff *skb,
349 					    struct genl_info *info)
350 {
351 	return __devlink_nl_pre_doit(skb, info,
352 				     DEVLINK_NL_FLAG_OPTIONAL_PARENT_DEV);
353 }
354 
__devlink_nl_post_doit(struct sk_buff * skb,struct genl_info * info,u8 flags)355 static void __devlink_nl_post_doit(struct sk_buff *skb, struct genl_info *info,
356 				   u8 flags)
357 {
358 	bool dev_lock = flags & DEVLINK_NL_FLAG_NEED_DEV_LOCK;
359 	struct devlink *devlink;
360 
361 	devlink = devlink_nl_ctx(info)->devlink;
362 	devl_dev_unlock(devlink, dev_lock);
363 	devlink_put(devlink);
364 	if (devlink_nl_ctx(info)->parent_devlink)
365 		devlink_put(devlink_nl_ctx(info)->parent_devlink);
366 }
367 
devlink_nl_post_doit(const struct genl_split_ops * ops,struct sk_buff * skb,struct genl_info * info)368 void devlink_nl_post_doit(const struct genl_split_ops *ops,
369 			  struct sk_buff *skb, struct genl_info *info)
370 {
371 	__devlink_nl_post_doit(skb, info, 0);
372 }
373 
374 void
devlink_nl_post_doit_dev_lock(const struct genl_split_ops * ops,struct sk_buff * skb,struct genl_info * info)375 devlink_nl_post_doit_dev_lock(const struct genl_split_ops *ops,
376 			      struct sk_buff *skb, struct genl_info *info)
377 {
378 	__devlink_nl_post_doit(skb, info, DEVLINK_NL_FLAG_NEED_DEV_LOCK);
379 }
380 
381 void
devlink_nl_post_doit_parent_dev_optional(const struct genl_split_ops * ops,struct sk_buff * skb,struct genl_info * info)382 devlink_nl_post_doit_parent_dev_optional(const struct genl_split_ops *ops,
383 					 struct sk_buff *skb,
384 					 struct genl_info *info)
385 {
386 	__devlink_nl_post_doit(skb, info, DEVLINK_NL_FLAG_OPTIONAL_PARENT_DEV);
387 }
388 
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)389 static int devlink_nl_inst_single_dumpit(struct sk_buff *msg,
390 					 struct netlink_callback *cb, int flags,
391 					 devlink_nl_dump_one_func_t *dump_one,
392 					 struct nlattr **attrs)
393 {
394 	struct devlink *devlink;
395 	int err;
396 
397 	devlink = devlink_get_from_attrs_lock(sock_net(msg->sk), attrs, false);
398 	if (IS_ERR(devlink))
399 		return PTR_ERR(devlink);
400 	err = dump_one(msg, devlink, cb, flags | NLM_F_DUMP_FILTERED);
401 
402 	devl_unlock(devlink);
403 	devlink_put(devlink);
404 
405 	if (err != -EMSGSIZE)
406 		return err;
407 	return msg->len;
408 }
409 
devlink_nl_inst_iter_dumpit(struct sk_buff * msg,struct netlink_callback * cb,int flags,devlink_nl_dump_one_func_t * dump_one)410 static int devlink_nl_inst_iter_dumpit(struct sk_buff *msg,
411 				       struct netlink_callback *cb, int flags,
412 				       devlink_nl_dump_one_func_t *dump_one)
413 {
414 	struct devlink_nl_dump_state *state = devlink_dump_state(cb);
415 	struct devlink *devlink;
416 	int err = 0;
417 
418 	while ((devlink = devlinks_xa_find_get(sock_net(msg->sk),
419 					       &state->instance))) {
420 		devl_lock(devlink);
421 
422 		if (devl_is_registered(devlink))
423 			err = dump_one(msg, devlink, cb, flags);
424 		else
425 			err = 0;
426 
427 		devl_unlock(devlink);
428 		devlink_put(devlink);
429 
430 		if (err)
431 			break;
432 
433 		state->instance++;
434 
435 		/* restart sub-object walk for the next instance */
436 		state->idx = 0;
437 		state->port_ctx.index = 0;
438 		state->port_ctx.index_valid = false;
439 	}
440 
441 	if (err != -EMSGSIZE)
442 		return err;
443 	return msg->len;
444 }
445 
devlink_nl_dumpit(struct sk_buff * msg,struct netlink_callback * cb,devlink_nl_dump_one_func_t * dump_one)446 int devlink_nl_dumpit(struct sk_buff *msg, struct netlink_callback *cb,
447 		      devlink_nl_dump_one_func_t *dump_one)
448 {
449 	const struct genl_info *info = genl_info_dump(cb);
450 	struct nlattr **attrs = info->attrs;
451 	int flags = NLM_F_MULTI;
452 
453 	if (attrs &&
454 	    (attrs[DEVLINK_ATTR_BUS_NAME] || attrs[DEVLINK_ATTR_DEV_NAME] ||
455 	     attrs[DEVLINK_ATTR_INDEX]))
456 		return devlink_nl_inst_single_dumpit(msg, cb, flags, dump_one,
457 						     attrs);
458 	else
459 		return devlink_nl_inst_iter_dumpit(msg, cb, flags, dump_one);
460 }
461 
462 struct genl_family devlink_nl_family __ro_after_init = {
463 	.name		= DEVLINK_GENL_NAME,
464 	.version	= DEVLINK_GENL_VERSION,
465 	.netnsok	= true,
466 	.parallel_ops	= true,
467 	.module		= THIS_MODULE,
468 	.split_ops	= devlink_nl_ops,
469 	.n_split_ops	= ARRAY_SIZE(devlink_nl_ops),
470 	.resv_start_op	= DEVLINK_CMD_SELFTESTS_RUN + 1,
471 	.mcgrps		= devlink_nl_mcgrps,
472 	.n_mcgrps	= ARRAY_SIZE(devlink_nl_mcgrps),
473 	.sock_priv_size		= sizeof(struct devlink_nl_sock_priv),
474 	.sock_priv_init		= devlink_nl_sock_priv_init,
475 	.sock_priv_destroy	= devlink_nl_sock_priv_destroy,
476 };
477