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.
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
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.
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>
26 #include "netdevsim.h"
28 static struct dentry
*nsim_dev_ddir
;
30 static int nsim_dev_debugfs_init(struct nsim_dev
*nsim_dev
)
32 char dev_ddir_name
[16];
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
;
44 static void nsim_dev_debugfs_exit(struct nsim_dev
*nsim_dev
)
46 debugfs_remove_recursive(nsim_dev
->ports_ddir
);
47 debugfs_remove_recursive(nsim_dev
->ddir
);
50 static int nsim_dev_port_debugfs_init(struct nsim_dev
*nsim_dev
,
51 struct nsim_dev_port
*nsim_dev_port
)
53 char port_ddir_name
[16];
54 char dev_link_name
[32];
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
))
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
);
69 static void nsim_dev_port_debugfs_exit(struct nsim_dev_port
*nsim_dev_port
)
71 debugfs_remove_recursive(nsim_dev_port
->ddir
);
74 static u64
nsim_dev_ipv4_fib_resource_occ_get(void *priv
)
76 struct nsim_dev
*nsim_dev
= priv
;
78 return nsim_fib_get_val(nsim_dev
->fib_data
,
79 NSIM_RESOURCE_IPV4_FIB
, false);
82 static u64
nsim_dev_ipv4_fib_rules_res_occ_get(void *priv
)
84 struct nsim_dev
*nsim_dev
= priv
;
86 return nsim_fib_get_val(nsim_dev
->fib_data
,
87 NSIM_RESOURCE_IPV4_FIB_RULES
, false);
90 static u64
nsim_dev_ipv6_fib_resource_occ_get(void *priv
)
92 struct nsim_dev
*nsim_dev
= priv
;
94 return nsim_fib_get_val(nsim_dev
->fib_data
,
95 NSIM_RESOURCE_IPV6_FIB
, false);
98 static u64
nsim_dev_ipv6_fib_rules_res_occ_get(void *priv
)
100 struct nsim_dev
*nsim_dev
= priv
;
102 return nsim_fib_get_val(nsim_dev
->fib_data
,
103 NSIM_RESOURCE_IPV6_FIB_RULES
, false);
106 static int nsim_dev_resources_register(struct devlink
*devlink
)
108 struct nsim_dev
*nsim_dev
= devlink_priv(devlink
);
109 struct devlink_resource_size_params params
= {
111 .size_granularity
= 1,
112 .unit
= DEVLINK_RESOURCE_UNIT_ENTRY
117 /* Resources for IPv4 */
118 err
= devlink_resource_register(devlink
, "IPv4", (u64
)-1,
120 DEVLINK_RESOURCE_ID_PARENT_TOP
,
123 pr_err("Failed to register IPv4 top resource\n");
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
, ¶ms
);
133 pr_err("Failed to register IPv4 FIB resource\n");
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
, ¶ms
);
143 pr_err("Failed to register IPv4 FIB rules resource\n");
147 /* Resources for IPv6 */
148 err
= devlink_resource_register(devlink
, "IPv6", (u64
)-1,
150 DEVLINK_RESOURCE_ID_PARENT_TOP
,
153 pr_err("Failed to register IPv6 top resource\n");
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
, ¶ms
);
163 pr_err("Failed to register IPv6 FIB resource\n");
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
, ¶ms
);
173 pr_err("Failed to register IPv6 FIB rules resource\n");
177 devlink_resource_occ_get_register(devlink
,
178 NSIM_RESOURCE_IPV4_FIB
,
179 nsim_dev_ipv4_fib_resource_occ_get
,
181 devlink_resource_occ_get_register(devlink
,
182 NSIM_RESOURCE_IPV4_FIB_RULES
,
183 nsim_dev_ipv4_fib_rules_res_occ_get
,
185 devlink_resource_occ_get_register(devlink
,
186 NSIM_RESOURCE_IPV6_FIB
,
187 nsim_dev_ipv6_fib_resource_occ_get
,
189 devlink_resource_occ_get_register(devlink
,
190 NSIM_RESOURCE_IPV6_FIB_RULES
,
191 nsim_dev_ipv6_fib_rules_res_occ_get
,
197 static int nsim_dev_reload(struct devlink
*devlink
,
198 struct netlink_ext_ack
*extack
)
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
207 for (i
= 0; i
< ARRAY_SIZE(res_ids
); ++i
) {
211 err
= devlink_resource_size_get(devlink
, res_ids
[i
], &val
);
213 err
= nsim_fib_set_max(nsim_dev
->fib_data
,
214 res_ids
[i
], val
, extack
);
223 static const struct devlink_ops nsim_dev_devlink_ops
= {
224 .reload
= nsim_dev_reload
,
227 static struct nsim_dev
*
228 nsim_dev_create(struct nsim_bus_dev
*nsim_bus_dev
, unsigned int port_count
)
230 struct nsim_dev
*nsim_dev
;
231 struct devlink
*devlink
;
234 devlink
= devlink_alloc(&nsim_dev_devlink_ops
, sizeof(*nsim_dev
));
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
);
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
;
250 err
= nsim_dev_resources_register(devlink
);
252 goto err_fib_destroy
;
254 err
= devlink_register(devlink
, &nsim_bus_dev
->dev
);
256 goto err_resources_unregister
;
258 err
= nsim_dev_debugfs_init(nsim_dev
);
260 goto err_dl_unregister
;
262 err
= nsim_bpf_dev_init(nsim_dev
);
264 goto err_debugfs_exit
;
269 nsim_dev_debugfs_exit(nsim_dev
);
271 devlink_unregister(devlink
);
272 err_resources_unregister
:
273 devlink_resources_unregister(devlink
, NULL
);
275 nsim_fib_destroy(nsim_dev
->fib_data
);
277 devlink_free(devlink
);
281 static void nsim_dev_destroy(struct nsim_dev
*nsim_dev
)
283 struct devlink
*devlink
= priv_to_devlink(nsim_dev
);
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
);
294 static int __nsim_dev_port_add(struct nsim_dev
*nsim_dev
,
295 unsigned int port_index
)
297 struct nsim_dev_port
*nsim_dev_port
;
298 struct devlink_port
*devlink_port
;
301 nsim_dev_port
= kzalloc(sizeof(*nsim_dev_port
), GFP_KERNEL
);
304 nsim_dev_port
->port_index
= port_index
;
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
,
316 err
= nsim_dev_port_debugfs_init(nsim_dev
, nsim_dev_port
);
318 goto err_dl_port_unregister
;
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
;
326 devlink_port_type_eth_set(devlink_port
, nsim_dev_port
->ns
->netdev
);
327 list_add(&nsim_dev_port
->list
, &nsim_dev
->port_list
);
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
);
336 kfree(nsim_dev_port
);
340 static void __nsim_dev_port_del(struct nsim_dev_port
*nsim_dev_port
)
342 struct devlink_port
*devlink_port
= &nsim_dev_port
->devlink_port
;
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
);
352 static void nsim_dev_port_del_all(struct nsim_dev
*nsim_dev
)
354 struct nsim_dev_port
*nsim_dev_port
, *tmp
;
356 list_for_each_entry_safe(nsim_dev_port
, tmp
,
357 &nsim_dev
->port_list
, list
)
358 __nsim_dev_port_del(nsim_dev_port
);
361 int nsim_dev_probe(struct nsim_bus_dev
*nsim_bus_dev
)
363 struct nsim_dev
*nsim_dev
;
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
);
372 for (i
= 0; i
< nsim_bus_dev
->port_count
; i
++) {
373 err
= __nsim_dev_port_add(nsim_dev
, i
);
375 goto err_port_del_all
;
380 nsim_dev_port_del_all(nsim_dev
);
381 nsim_dev_destroy(nsim_dev
);
385 void nsim_dev_remove(struct nsim_bus_dev
*nsim_bus_dev
)
387 struct nsim_dev
*nsim_dev
= dev_get_drvdata(&nsim_bus_dev
->dev
);
389 nsim_dev_port_del_all(nsim_dev
);
390 nsim_dev_destroy(nsim_dev
);
393 static struct nsim_dev_port
*
394 __nsim_dev_port_lookup(struct nsim_dev
*nsim_dev
, unsigned int port_index
)
396 struct nsim_dev_port
*nsim_dev_port
;
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
;
404 int nsim_dev_port_add(struct nsim_bus_dev
*nsim_bus_dev
,
405 unsigned int port_index
)
407 struct nsim_dev
*nsim_dev
= dev_get_drvdata(&nsim_bus_dev
->dev
);
410 mutex_lock(&nsim_dev
->port_list_lock
);
411 if (__nsim_dev_port_lookup(nsim_dev
, port_index
))
414 err
= __nsim_dev_port_add(nsim_dev
, port_index
);
415 mutex_unlock(&nsim_dev
->port_list_lock
);
419 int nsim_dev_port_del(struct nsim_bus_dev
*nsim_bus_dev
,
420 unsigned int port_index
)
422 struct nsim_dev
*nsim_dev
= dev_get_drvdata(&nsim_bus_dev
->dev
);
423 struct nsim_dev_port
*nsim_dev_port
;
426 mutex_lock(&nsim_dev
->port_list_lock
);
427 nsim_dev_port
= __nsim_dev_port_lookup(nsim_dev
, port_index
);
431 __nsim_dev_port_del(nsim_dev_port
);
432 mutex_unlock(&nsim_dev
->port_list_lock
);
436 int nsim_dev_init(void)
438 nsim_dev_ddir
= debugfs_create_dir(DRV_NAME
, NULL
);
439 if (IS_ERR_OR_NULL(nsim_dev_ddir
))
444 void nsim_dev_exit(void)
446 debugfs_remove_recursive(nsim_dev_ddir
);