blob: 27ae05c5fdafe66a70f250471f3d0a416b00a90b [file] [log] [blame]
David Ahern37923ed2018-03-27 18:22:00 -07001/*
2 * Copyright (c) 2018 Cumulus Networks. All rights reserved.
3 * Copyright (c) 2018 David Ahern <dsa@cumulusnetworks.com>
4 *
5 * This software is licensed under the GNU General License Version 2,
6 * June 1991 as shown in the file COPYING in the top-level directory of this
7 * source tree.
8 *
9 * THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS"
10 * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
11 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
12 * FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
13 * OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
14 * THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
15 */
16
17#include <linux/device.h>
18#include <net/devlink.h>
19#include <net/netns/generic.h>
20
21#include "netdevsim.h"
22
23static unsigned int nsim_devlink_id;
24
25/* place holder until devlink and namespaces is sorted out */
26static struct net *nsim_devlink_net(struct devlink *devlink)
27{
28 return &init_net;
29}
30
31/* IPv4
32 */
33static u64 nsim_ipv4_fib_resource_occ_get(struct devlink *devlink)
34{
35 struct net *net = nsim_devlink_net(devlink);
36
37 return nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB, false);
38}
39
40static struct devlink_resource_ops nsim_ipv4_fib_res_ops = {
41 .occ_get = nsim_ipv4_fib_resource_occ_get,
42};
43
44static u64 nsim_ipv4_fib_rules_res_occ_get(struct devlink *devlink)
45{
46 struct net *net = nsim_devlink_net(devlink);
47
48 return nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB_RULES, false);
49}
50
51static struct devlink_resource_ops nsim_ipv4_fib_rules_res_ops = {
52 .occ_get = nsim_ipv4_fib_rules_res_occ_get,
53};
54
55/* IPv6
56 */
57static u64 nsim_ipv6_fib_resource_occ_get(struct devlink *devlink)
58{
59 struct net *net = nsim_devlink_net(devlink);
60
61 return nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB, false);
62}
63
64static struct devlink_resource_ops nsim_ipv6_fib_res_ops = {
65 .occ_get = nsim_ipv6_fib_resource_occ_get,
66};
67
68static u64 nsim_ipv6_fib_rules_res_occ_get(struct devlink *devlink)
69{
70 struct net *net = nsim_devlink_net(devlink);
71
72 return nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB_RULES, false);
73}
74
75static struct devlink_resource_ops nsim_ipv6_fib_rules_res_ops = {
76 .occ_get = nsim_ipv6_fib_rules_res_occ_get,
77};
78
79static int devlink_resources_register(struct devlink *devlink)
80{
81 struct devlink_resource_size_params params = {
82 .size_max = (u64)-1,
83 .size_granularity = 1,
84 .unit = DEVLINK_RESOURCE_UNIT_ENTRY
85 };
86 struct net *net = nsim_devlink_net(devlink);
87 int err;
88 u64 n;
89
90 /* Resources for IPv4 */
91 err = devlink_resource_register(devlink, "IPv4", (u64)-1,
92 NSIM_RESOURCE_IPV4,
93 DEVLINK_RESOURCE_ID_PARENT_TOP,
94 &params, NULL);
95 if (err) {
96 pr_err("Failed to register IPv4 top resource\n");
97 goto out;
98 }
99
100 n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB, true);
101 err = devlink_resource_register(devlink, "fib", n,
102 NSIM_RESOURCE_IPV4_FIB,
103 NSIM_RESOURCE_IPV4,
104 &params, &nsim_ipv4_fib_res_ops);
105 if (err) {
106 pr_err("Failed to register IPv4 FIB resource\n");
107 return err;
108 }
109
110 n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB_RULES, true);
111 err = devlink_resource_register(devlink, "fib-rules", n,
112 NSIM_RESOURCE_IPV4_FIB_RULES,
113 NSIM_RESOURCE_IPV4,
114 &params, &nsim_ipv4_fib_rules_res_ops);
115 if (err) {
116 pr_err("Failed to register IPv4 FIB rules resource\n");
117 return err;
118 }
119
120 /* Resources for IPv6 */
121 err = devlink_resource_register(devlink, "IPv6", (u64)-1,
122 NSIM_RESOURCE_IPV6,
123 DEVLINK_RESOURCE_ID_PARENT_TOP,
124 &params, NULL);
125 if (err) {
126 pr_err("Failed to register IPv6 top resource\n");
127 goto out;
128 }
129
130 n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB, true);
131 err = devlink_resource_register(devlink, "fib", n,
132 NSIM_RESOURCE_IPV6_FIB,
133 NSIM_RESOURCE_IPV6,
134 &params, &nsim_ipv6_fib_res_ops);
135 if (err) {
136 pr_err("Failed to register IPv6 FIB resource\n");
137 return err;
138 }
139
140 n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB_RULES, true);
141 err = devlink_resource_register(devlink, "fib-rules", n,
142 NSIM_RESOURCE_IPV6_FIB_RULES,
143 NSIM_RESOURCE_IPV6,
144 &params, &nsim_ipv6_fib_rules_res_ops);
145 if (err) {
146 pr_err("Failed to register IPv6 FIB rules resource\n");
147 return err;
148 }
149out:
150 return err;
151}
152
153static int nsim_devlink_reload(struct devlink *devlink)
154{
155 enum nsim_resource_id res_ids[] = {
156 NSIM_RESOURCE_IPV4_FIB, NSIM_RESOURCE_IPV4_FIB_RULES,
157 NSIM_RESOURCE_IPV6_FIB, NSIM_RESOURCE_IPV6_FIB_RULES
158 };
159 struct net *net = nsim_devlink_net(devlink);
160 int i;
161
162 for (i = 0; i < ARRAY_SIZE(res_ids); ++i) {
163 int err;
164 u64 val;
165
166 err = devlink_resource_size_get(devlink, res_ids[i], &val);
167 if (!err) {
168 err = nsim_fib_set_max(net, res_ids[i], val);
169 if (err)
170 return err;
171 }
172 }
173
174 return 0;
175}
176
177static void nsim_devlink_net_reset(struct net *net)
178{
179 enum nsim_resource_id res_ids[] = {
180 NSIM_RESOURCE_IPV4_FIB, NSIM_RESOURCE_IPV4_FIB_RULES,
181 NSIM_RESOURCE_IPV6_FIB, NSIM_RESOURCE_IPV6_FIB_RULES
182 };
183 int i;
184
185 for (i = 0; i < ARRAY_SIZE(res_ids); ++i) {
186 if (nsim_fib_set_max(net, res_ids[i], (u64)-1)) {
187 pr_err("Failed to reset limit for resource %u\n",
188 res_ids[i]);
189 }
190 }
191}
192
193static const struct devlink_ops nsim_devlink_ops = {
194 .reload = nsim_devlink_reload,
195};
196
197/* once devlink / namespace issues are sorted out
198 * this needs to be net in which a devlink instance
199 * is to be created. e.g., dev_net(ns->netdev)
200 */
201static struct net *nsim_to_net(struct netdevsim *ns)
202{
203 return &init_net;
204}
205
206void nsim_devlink_teardown(struct netdevsim *ns)
207{
208 if (ns->devlink) {
209 struct net *net = nsim_to_net(ns);
210 bool *reg_devlink = net_generic(net, nsim_devlink_id);
211
212 devlink_unregister(ns->devlink);
213 devlink_free(ns->devlink);
214 ns->devlink = NULL;
215
216 nsim_devlink_net_reset(net);
217 *reg_devlink = true;
218 }
219}
220
David Ahernef817102018-03-30 09:28:51 -0700221int nsim_devlink_setup(struct netdevsim *ns)
David Ahern37923ed2018-03-27 18:22:00 -0700222{
223 struct net *net = nsim_to_net(ns);
224 bool *reg_devlink = net_generic(net, nsim_devlink_id);
225 struct devlink *devlink;
David Ahernef817102018-03-30 09:28:51 -0700226 int err;
David Ahern37923ed2018-03-27 18:22:00 -0700227
228 /* only one device per namespace controls devlink */
229 if (!*reg_devlink) {
230 ns->devlink = NULL;
David Ahernef817102018-03-30 09:28:51 -0700231 return 0;
David Ahern37923ed2018-03-27 18:22:00 -0700232 }
233
234 devlink = devlink_alloc(&nsim_devlink_ops, 0);
235 if (!devlink)
David Ahernef817102018-03-30 09:28:51 -0700236 return -ENOMEM;
David Ahern37923ed2018-03-27 18:22:00 -0700237
238 err = devlink_register(devlink, &ns->dev);
239 if (err)
240 goto err_devlink_free;
241
242 err = devlink_resources_register(devlink);
243 if (err)
244 goto err_dl_unregister;
245
246 ns->devlink = devlink;
247
248 *reg_devlink = false;
249
David Ahernef817102018-03-30 09:28:51 -0700250 return 0;
David Ahern37923ed2018-03-27 18:22:00 -0700251
252err_dl_unregister:
253 devlink_unregister(devlink);
254err_devlink_free:
255 devlink_free(devlink);
David Ahernef817102018-03-30 09:28:51 -0700256
257 return err;
David Ahern37923ed2018-03-27 18:22:00 -0700258}
259
260/* Initialize per network namespace state */
261static int __net_init nsim_devlink_netns_init(struct net *net)
262{
263 bool *reg_devlink = net_generic(net, nsim_devlink_id);
264
265 *reg_devlink = true;
266
267 return 0;
268}
269
270static struct pernet_operations nsim_devlink_net_ops __net_initdata = {
271 .init = nsim_devlink_netns_init,
272 .id = &nsim_devlink_id,
273 .size = sizeof(bool),
274};
275
276void nsim_devlink_exit(void)
277{
278 unregister_pernet_subsys(&nsim_devlink_net_ops);
279 nsim_fib_exit();
280}
281
282int nsim_devlink_init(void)
283{
284 int err;
285
286 err = nsim_fib_init();
287 if (err)
288 goto err_out;
289
290 err = register_pernet_subsys(&nsim_devlink_net_ops);
291 if (err)
292 nsim_fib_exit();
293
294err_out:
295 return err;
296}