xref: /openbmc/linux/drivers/net/netdevsim/dev.c (revision b664e06d)
1 /*
2  * Copyright (c) 2018 Cumulus Networks. All rights reserved.
3  * Copyright (c) 2018 David Ahern <dsa@cumulusnetworks.com>
4  * Copyright (c) 2019 Mellanox Technologies. All rights reserved.
5  *
6  * This software is licensed under the GNU General License Version 2,
7  * June 1991 as shown in the file COPYING in the top-level directory of this
8  * source tree.
9  *
10  * THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS"
11  * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
12  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
13  * FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
14  * OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
15  * THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16  */
17 
18 #include <linux/debugfs.h>
19 #include <linux/device.h>
20 #include <linux/list.h>
21 #include <linux/mutex.h>
22 #include <linux/random.h>
23 #include <linux/rtnetlink.h>
24 #include <net/devlink.h>
25 
26 #include "netdevsim.h"
27 
28 static struct dentry *nsim_dev_ddir;
29 
30 static int nsim_dev_debugfs_init(struct nsim_dev *nsim_dev)
31 {
32 	char dev_ddir_name[16];
33 
34 	sprintf(dev_ddir_name, DRV_NAME "%u", nsim_dev->nsim_bus_dev->dev.id);
35 	nsim_dev->ddir = debugfs_create_dir(dev_ddir_name, nsim_dev_ddir);
36 	if (IS_ERR_OR_NULL(nsim_dev->ddir))
37 		return PTR_ERR_OR_ZERO(nsim_dev->ddir) ?: -EINVAL;
38 	nsim_dev->ports_ddir = debugfs_create_dir("ports", nsim_dev->ddir);
39 	if (IS_ERR_OR_NULL(nsim_dev->ports_ddir))
40 		return PTR_ERR_OR_ZERO(nsim_dev->ports_ddir) ?: -EINVAL;
41 	return 0;
42 }
43 
44 static void nsim_dev_debugfs_exit(struct nsim_dev *nsim_dev)
45 {
46 	debugfs_remove_recursive(nsim_dev->ports_ddir);
47 	debugfs_remove_recursive(nsim_dev->ddir);
48 }
49 
50 static int nsim_dev_port_debugfs_init(struct nsim_dev *nsim_dev,
51 				      struct nsim_dev_port *nsim_dev_port)
52 {
53 	char port_ddir_name[16];
54 	char dev_link_name[32];
55 
56 	sprintf(port_ddir_name, "%u", nsim_dev_port->port_index);
57 	nsim_dev_port->ddir = debugfs_create_dir(port_ddir_name,
58 						 nsim_dev->ports_ddir);
59 	if (IS_ERR_OR_NULL(nsim_dev_port->ddir))
60 		return -ENOMEM;
61 
62 	sprintf(dev_link_name, "../../../" DRV_NAME "%u",
63 		nsim_dev->nsim_bus_dev->dev.id);
64 	debugfs_create_symlink("dev", nsim_dev_port->ddir, dev_link_name);
65 
66 	return 0;
67 }
68 
69 static void nsim_dev_port_debugfs_exit(struct nsim_dev_port *nsim_dev_port)
70 {
71 	debugfs_remove_recursive(nsim_dev_port->ddir);
72 }
73 
74 static u64 nsim_dev_ipv4_fib_resource_occ_get(void *priv)
75 {
76 	struct nsim_dev *nsim_dev = priv;
77 
78 	return nsim_fib_get_val(nsim_dev->fib_data,
79 				NSIM_RESOURCE_IPV4_FIB, false);
80 }
81 
82 static u64 nsim_dev_ipv4_fib_rules_res_occ_get(void *priv)
83 {
84 	struct nsim_dev *nsim_dev = priv;
85 
86 	return nsim_fib_get_val(nsim_dev->fib_data,
87 				NSIM_RESOURCE_IPV4_FIB_RULES, false);
88 }
89 
90 static u64 nsim_dev_ipv6_fib_resource_occ_get(void *priv)
91 {
92 	struct nsim_dev *nsim_dev = priv;
93 
94 	return nsim_fib_get_val(nsim_dev->fib_data,
95 				NSIM_RESOURCE_IPV6_FIB, false);
96 }
97 
98 static u64 nsim_dev_ipv6_fib_rules_res_occ_get(void *priv)
99 {
100 	struct nsim_dev *nsim_dev = priv;
101 
102 	return nsim_fib_get_val(nsim_dev->fib_data,
103 				NSIM_RESOURCE_IPV6_FIB_RULES, false);
104 }
105 
106 static int nsim_dev_resources_register(struct devlink *devlink)
107 {
108 	struct nsim_dev *nsim_dev = devlink_priv(devlink);
109 	struct devlink_resource_size_params params = {
110 		.size_max = (u64)-1,
111 		.size_granularity = 1,
112 		.unit = DEVLINK_RESOURCE_UNIT_ENTRY
113 	};
114 	int err;
115 	u64 n;
116 
117 	/* Resources for IPv4 */
118 	err = devlink_resource_register(devlink, "IPv4", (u64)-1,
119 					NSIM_RESOURCE_IPV4,
120 					DEVLINK_RESOURCE_ID_PARENT_TOP,
121 					&params);
122 	if (err) {
123 		pr_err("Failed to register IPv4 top resource\n");
124 		goto out;
125 	}
126 
127 	n = nsim_fib_get_val(nsim_dev->fib_data,
128 			     NSIM_RESOURCE_IPV4_FIB, true);
129 	err = devlink_resource_register(devlink, "fib", n,
130 					NSIM_RESOURCE_IPV4_FIB,
131 					NSIM_RESOURCE_IPV4, &params);
132 	if (err) {
133 		pr_err("Failed to register IPv4 FIB resource\n");
134 		return err;
135 	}
136 
137 	n = nsim_fib_get_val(nsim_dev->fib_data,
138 			     NSIM_RESOURCE_IPV4_FIB_RULES, true);
139 	err = devlink_resource_register(devlink, "fib-rules", n,
140 					NSIM_RESOURCE_IPV4_FIB_RULES,
141 					NSIM_RESOURCE_IPV4, &params);
142 	if (err) {
143 		pr_err("Failed to register IPv4 FIB rules resource\n");
144 		return err;
145 	}
146 
147 	/* Resources for IPv6 */
148 	err = devlink_resource_register(devlink, "IPv6", (u64)-1,
149 					NSIM_RESOURCE_IPV6,
150 					DEVLINK_RESOURCE_ID_PARENT_TOP,
151 					&params);
152 	if (err) {
153 		pr_err("Failed to register IPv6 top resource\n");
154 		goto out;
155 	}
156 
157 	n = nsim_fib_get_val(nsim_dev->fib_data,
158 			     NSIM_RESOURCE_IPV6_FIB, true);
159 	err = devlink_resource_register(devlink, "fib", n,
160 					NSIM_RESOURCE_IPV6_FIB,
161 					NSIM_RESOURCE_IPV6, &params);
162 	if (err) {
163 		pr_err("Failed to register IPv6 FIB resource\n");
164 		return err;
165 	}
166 
167 	n = nsim_fib_get_val(nsim_dev->fib_data,
168 			     NSIM_RESOURCE_IPV6_FIB_RULES, true);
169 	err = devlink_resource_register(devlink, "fib-rules", n,
170 					NSIM_RESOURCE_IPV6_FIB_RULES,
171 					NSIM_RESOURCE_IPV6, &params);
172 	if (err) {
173 		pr_err("Failed to register IPv6 FIB rules resource\n");
174 		return err;
175 	}
176 
177 	devlink_resource_occ_get_register(devlink,
178 					  NSIM_RESOURCE_IPV4_FIB,
179 					  nsim_dev_ipv4_fib_resource_occ_get,
180 					  nsim_dev);
181 	devlink_resource_occ_get_register(devlink,
182 					  NSIM_RESOURCE_IPV4_FIB_RULES,
183 					  nsim_dev_ipv4_fib_rules_res_occ_get,
184 					  nsim_dev);
185 	devlink_resource_occ_get_register(devlink,
186 					  NSIM_RESOURCE_IPV6_FIB,
187 					  nsim_dev_ipv6_fib_resource_occ_get,
188 					  nsim_dev);
189 	devlink_resource_occ_get_register(devlink,
190 					  NSIM_RESOURCE_IPV6_FIB_RULES,
191 					  nsim_dev_ipv6_fib_rules_res_occ_get,
192 					  nsim_dev);
193 out:
194 	return err;
195 }
196 
197 static int nsim_dev_reload(struct devlink *devlink,
198 			   struct netlink_ext_ack *extack)
199 {
200 	struct nsim_dev *nsim_dev = devlink_priv(devlink);
201 	enum nsim_resource_id res_ids[] = {
202 		NSIM_RESOURCE_IPV4_FIB, NSIM_RESOURCE_IPV4_FIB_RULES,
203 		NSIM_RESOURCE_IPV6_FIB, NSIM_RESOURCE_IPV6_FIB_RULES
204 	};
205 	int i;
206 
207 	for (i = 0; i < ARRAY_SIZE(res_ids); ++i) {
208 		int err;
209 		u64 val;
210 
211 		err = devlink_resource_size_get(devlink, res_ids[i], &val);
212 		if (!err) {
213 			err = nsim_fib_set_max(nsim_dev->fib_data,
214 					       res_ids[i], val, extack);
215 			if (err)
216 				return err;
217 		}
218 	}
219 
220 	return 0;
221 }
222 
223 static const struct devlink_ops nsim_dev_devlink_ops = {
224 	.reload = nsim_dev_reload,
225 };
226 
227 static struct nsim_dev *
228 nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev, unsigned int port_count)
229 {
230 	struct nsim_dev *nsim_dev;
231 	struct devlink *devlink;
232 	int err;
233 
234 	devlink = devlink_alloc(&nsim_dev_devlink_ops, sizeof(*nsim_dev));
235 	if (!devlink)
236 		return ERR_PTR(-ENOMEM);
237 	nsim_dev = devlink_priv(devlink);
238 	nsim_dev->nsim_bus_dev = nsim_bus_dev;
239 	nsim_dev->switch_id.id_len = sizeof(nsim_dev->switch_id.id);
240 	get_random_bytes(nsim_dev->switch_id.id, nsim_dev->switch_id.id_len);
241 	INIT_LIST_HEAD(&nsim_dev->port_list);
242 	mutex_init(&nsim_dev->port_list_lock);
243 
244 	nsim_dev->fib_data = nsim_fib_create();
245 	if (IS_ERR(nsim_dev->fib_data)) {
246 		err = PTR_ERR(nsim_dev->fib_data);
247 		goto err_devlink_free;
248 	}
249 
250 	err = nsim_dev_resources_register(devlink);
251 	if (err)
252 		goto err_fib_destroy;
253 
254 	err = devlink_register(devlink, &nsim_bus_dev->dev);
255 	if (err)
256 		goto err_resources_unregister;
257 
258 	err = nsim_dev_debugfs_init(nsim_dev);
259 	if (err)
260 		goto err_dl_unregister;
261 
262 	err = nsim_bpf_dev_init(nsim_dev);
263 	if (err)
264 		goto err_debugfs_exit;
265 
266 	return nsim_dev;
267 
268 err_debugfs_exit:
269 	nsim_dev_debugfs_exit(nsim_dev);
270 err_dl_unregister:
271 	devlink_unregister(devlink);
272 err_resources_unregister:
273 	devlink_resources_unregister(devlink, NULL);
274 err_fib_destroy:
275 	nsim_fib_destroy(nsim_dev->fib_data);
276 err_devlink_free:
277 	devlink_free(devlink);
278 	return ERR_PTR(err);
279 }
280 
281 static void nsim_dev_destroy(struct nsim_dev *nsim_dev)
282 {
283 	struct devlink *devlink = priv_to_devlink(nsim_dev);
284 
285 	nsim_bpf_dev_exit(nsim_dev);
286 	nsim_dev_debugfs_exit(nsim_dev);
287 	devlink_unregister(devlink);
288 	devlink_resources_unregister(devlink, NULL);
289 	nsim_fib_destroy(nsim_dev->fib_data);
290 	mutex_destroy(&nsim_dev->port_list_lock);
291 	devlink_free(devlink);
292 }
293 
294 static int __nsim_dev_port_add(struct nsim_dev *nsim_dev,
295 			       unsigned int port_index)
296 {
297 	struct nsim_dev_port *nsim_dev_port;
298 	struct devlink_port *devlink_port;
299 	int err;
300 
301 	nsim_dev_port = kzalloc(sizeof(*nsim_dev_port), GFP_KERNEL);
302 	if (!nsim_dev_port)
303 		return -ENOMEM;
304 	nsim_dev_port->port_index = port_index;
305 
306 	devlink_port = &nsim_dev_port->devlink_port;
307 	devlink_port_attrs_set(devlink_port, DEVLINK_PORT_FLAVOUR_PHYSICAL,
308 			       port_index + 1, 0, 0,
309 			       nsim_dev->switch_id.id,
310 			       nsim_dev->switch_id.id_len);
311 	err = devlink_port_register(priv_to_devlink(nsim_dev), devlink_port,
312 				    port_index);
313 	if (err)
314 		goto err_port_free;
315 
316 	err = nsim_dev_port_debugfs_init(nsim_dev, nsim_dev_port);
317 	if (err)
318 		goto err_dl_port_unregister;
319 
320 	nsim_dev_port->ns = nsim_create(nsim_dev, nsim_dev_port);
321 	if (IS_ERR(nsim_dev_port->ns)) {
322 		err = PTR_ERR(nsim_dev_port->ns);
323 		goto err_port_debugfs_exit;
324 	}
325 
326 	devlink_port_type_eth_set(devlink_port, nsim_dev_port->ns->netdev);
327 	list_add(&nsim_dev_port->list, &nsim_dev->port_list);
328 
329 	return 0;
330 
331 err_port_debugfs_exit:
332 	nsim_dev_port_debugfs_exit(nsim_dev_port);
333 err_dl_port_unregister:
334 	devlink_port_unregister(devlink_port);
335 err_port_free:
336 	kfree(nsim_dev_port);
337 	return err;
338 }
339 
340 static void __nsim_dev_port_del(struct nsim_dev_port *nsim_dev_port)
341 {
342 	struct devlink_port *devlink_port = &nsim_dev_port->devlink_port;
343 
344 	list_del(&nsim_dev_port->list);
345 	devlink_port_type_clear(devlink_port);
346 	nsim_destroy(nsim_dev_port->ns);
347 	nsim_dev_port_debugfs_exit(nsim_dev_port);
348 	devlink_port_unregister(devlink_port);
349 	kfree(nsim_dev_port);
350 }
351 
352 static void nsim_dev_port_del_all(struct nsim_dev *nsim_dev)
353 {
354 	struct nsim_dev_port *nsim_dev_port, *tmp;
355 
356 	list_for_each_entry_safe(nsim_dev_port, tmp,
357 				 &nsim_dev->port_list, list)
358 		__nsim_dev_port_del(nsim_dev_port);
359 }
360 
361 int nsim_dev_probe(struct nsim_bus_dev *nsim_bus_dev)
362 {
363 	struct nsim_dev *nsim_dev;
364 	int i;
365 	int err;
366 
367 	nsim_dev = nsim_dev_create(nsim_bus_dev, nsim_bus_dev->port_count);
368 	if (IS_ERR(nsim_dev))
369 		return PTR_ERR(nsim_dev);
370 	dev_set_drvdata(&nsim_bus_dev->dev, nsim_dev);
371 
372 	for (i = 0; i < nsim_bus_dev->port_count; i++) {
373 		err = __nsim_dev_port_add(nsim_dev, i);
374 		if (err)
375 			goto err_port_del_all;
376 	}
377 	return 0;
378 
379 err_port_del_all:
380 	nsim_dev_port_del_all(nsim_dev);
381 	nsim_dev_destroy(nsim_dev);
382 	return err;
383 }
384 
385 void nsim_dev_remove(struct nsim_bus_dev *nsim_bus_dev)
386 {
387 	struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev);
388 
389 	nsim_dev_port_del_all(nsim_dev);
390 	nsim_dev_destroy(nsim_dev);
391 }
392 
393 static struct nsim_dev_port *
394 __nsim_dev_port_lookup(struct nsim_dev *nsim_dev, unsigned int port_index)
395 {
396 	struct nsim_dev_port *nsim_dev_port;
397 
398 	list_for_each_entry(nsim_dev_port, &nsim_dev->port_list, list)
399 		if (nsim_dev_port->port_index == port_index)
400 			return nsim_dev_port;
401 	return NULL;
402 }
403 
404 int nsim_dev_port_add(struct nsim_bus_dev *nsim_bus_dev,
405 		      unsigned int port_index)
406 {
407 	struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev);
408 	int err;
409 
410 	mutex_lock(&nsim_dev->port_list_lock);
411 	if (__nsim_dev_port_lookup(nsim_dev, port_index))
412 		err = -EEXIST;
413 	else
414 		err = __nsim_dev_port_add(nsim_dev, port_index);
415 	mutex_unlock(&nsim_dev->port_list_lock);
416 	return err;
417 }
418 
419 int nsim_dev_port_del(struct nsim_bus_dev *nsim_bus_dev,
420 		      unsigned int port_index)
421 {
422 	struct nsim_dev *nsim_dev = dev_get_drvdata(&nsim_bus_dev->dev);
423 	struct nsim_dev_port *nsim_dev_port;
424 	int err = 0;
425 
426 	mutex_lock(&nsim_dev->port_list_lock);
427 	nsim_dev_port = __nsim_dev_port_lookup(nsim_dev, port_index);
428 	if (!nsim_dev_port)
429 		err = -ENOENT;
430 	else
431 		__nsim_dev_port_del(nsim_dev_port);
432 	mutex_unlock(&nsim_dev->port_list_lock);
433 	return err;
434 }
435 
436 int nsim_dev_init(void)
437 {
438 	nsim_dev_ddir = debugfs_create_dir(DRV_NAME, NULL);
439 	if (IS_ERR_OR_NULL(nsim_dev_ddir))
440 		return -ENOMEM;
441 	return 0;
442 }
443 
444 void nsim_dev_exit(void)
445 {
446 	debugfs_remove_recursive(nsim_dev_ddir);
447 }
448