blob: ba663e5af168bc4db3152f6a8fdaf85bf4753148 [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 */
Jiri Pirkofc56be42018-04-05 22:13:21 +020033static u64 nsim_ipv4_fib_resource_occ_get(void *priv)
David Ahern37923ed2018-03-27 18:22:00 -070034{
Jiri Pirkofc56be42018-04-05 22:13:21 +020035 struct net *net = priv;
David Ahern37923ed2018-03-27 18:22:00 -070036
37 return nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB, false);
38}
39
Jiri Pirkofc56be42018-04-05 22:13:21 +020040static u64 nsim_ipv4_fib_rules_res_occ_get(void *priv)
David Ahern37923ed2018-03-27 18:22:00 -070041{
Jiri Pirkofc56be42018-04-05 22:13:21 +020042 struct net *net = priv;
David Ahern37923ed2018-03-27 18:22:00 -070043
44 return nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB_RULES, false);
45}
46
David Ahern37923ed2018-03-27 18:22:00 -070047/* IPv6
48 */
Jiri Pirkofc56be42018-04-05 22:13:21 +020049static u64 nsim_ipv6_fib_resource_occ_get(void *priv)
David Ahern37923ed2018-03-27 18:22:00 -070050{
Jiri Pirkofc56be42018-04-05 22:13:21 +020051 struct net *net = priv;
David Ahern37923ed2018-03-27 18:22:00 -070052
53 return nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB, false);
54}
55
Jiri Pirkofc56be42018-04-05 22:13:21 +020056static u64 nsim_ipv6_fib_rules_res_occ_get(void *priv)
David Ahern37923ed2018-03-27 18:22:00 -070057{
Jiri Pirkofc56be42018-04-05 22:13:21 +020058 struct net *net = priv;
David Ahern37923ed2018-03-27 18:22:00 -070059
60 return nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB_RULES, false);
61}
62
David Ahern37923ed2018-03-27 18:22:00 -070063static int devlink_resources_register(struct devlink *devlink)
64{
65 struct devlink_resource_size_params params = {
66 .size_max = (u64)-1,
67 .size_granularity = 1,
68 .unit = DEVLINK_RESOURCE_UNIT_ENTRY
69 };
70 struct net *net = nsim_devlink_net(devlink);
71 int err;
72 u64 n;
73
74 /* Resources for IPv4 */
75 err = devlink_resource_register(devlink, "IPv4", (u64)-1,
76 NSIM_RESOURCE_IPV4,
77 DEVLINK_RESOURCE_ID_PARENT_TOP,
Jiri Pirkofc56be42018-04-05 22:13:21 +020078 &params);
David Ahern37923ed2018-03-27 18:22:00 -070079 if (err) {
80 pr_err("Failed to register IPv4 top resource\n");
81 goto out;
82 }
83
84 n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB, true);
85 err = devlink_resource_register(devlink, "fib", n,
86 NSIM_RESOURCE_IPV4_FIB,
Jiri Pirkofc56be42018-04-05 22:13:21 +020087 NSIM_RESOURCE_IPV4, &params);
David Ahern37923ed2018-03-27 18:22:00 -070088 if (err) {
89 pr_err("Failed to register IPv4 FIB resource\n");
90 return err;
91 }
92
93 n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB_RULES, true);
94 err = devlink_resource_register(devlink, "fib-rules", n,
95 NSIM_RESOURCE_IPV4_FIB_RULES,
Jiri Pirkofc56be42018-04-05 22:13:21 +020096 NSIM_RESOURCE_IPV4, &params);
David Ahern37923ed2018-03-27 18:22:00 -070097 if (err) {
98 pr_err("Failed to register IPv4 FIB rules resource\n");
99 return err;
100 }
101
102 /* Resources for IPv6 */
103 err = devlink_resource_register(devlink, "IPv6", (u64)-1,
104 NSIM_RESOURCE_IPV6,
105 DEVLINK_RESOURCE_ID_PARENT_TOP,
Jiri Pirkofc56be42018-04-05 22:13:21 +0200106 &params);
David Ahern37923ed2018-03-27 18:22:00 -0700107 if (err) {
108 pr_err("Failed to register IPv6 top resource\n");
109 goto out;
110 }
111
112 n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB, true);
113 err = devlink_resource_register(devlink, "fib", n,
114 NSIM_RESOURCE_IPV6_FIB,
Jiri Pirkofc56be42018-04-05 22:13:21 +0200115 NSIM_RESOURCE_IPV6, &params);
David Ahern37923ed2018-03-27 18:22:00 -0700116 if (err) {
117 pr_err("Failed to register IPv6 FIB resource\n");
118 return err;
119 }
120
121 n = nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB_RULES, true);
122 err = devlink_resource_register(devlink, "fib-rules", n,
123 NSIM_RESOURCE_IPV6_FIB_RULES,
Jiri Pirkofc56be42018-04-05 22:13:21 +0200124 NSIM_RESOURCE_IPV6, &params);
David Ahern37923ed2018-03-27 18:22:00 -0700125 if (err) {
126 pr_err("Failed to register IPv6 FIB rules resource\n");
127 return err;
128 }
Jiri Pirkofc56be42018-04-05 22:13:21 +0200129
130 devlink_resource_occ_get_register(devlink,
131 NSIM_RESOURCE_IPV4_FIB,
132 nsim_ipv4_fib_resource_occ_get,
133 net);
134 devlink_resource_occ_get_register(devlink,
135 NSIM_RESOURCE_IPV4_FIB_RULES,
136 nsim_ipv4_fib_rules_res_occ_get,
137 net);
138 devlink_resource_occ_get_register(devlink,
139 NSIM_RESOURCE_IPV6_FIB,
140 nsim_ipv6_fib_resource_occ_get,
141 net);
142 devlink_resource_occ_get_register(devlink,
143 NSIM_RESOURCE_IPV6_FIB_RULES,
144 nsim_ipv6_fib_rules_res_occ_get,
145 net);
David Ahern37923ed2018-03-27 18:22:00 -0700146out:
147 return err;
148}
149
David Ahernac0fc8a2018-06-05 08:14:09 -0700150static int nsim_devlink_reload(struct devlink *devlink,
151 struct netlink_ext_ack *extack)
David Ahern37923ed2018-03-27 18:22:00 -0700152{
153 enum nsim_resource_id res_ids[] = {
154 NSIM_RESOURCE_IPV4_FIB, NSIM_RESOURCE_IPV4_FIB_RULES,
155 NSIM_RESOURCE_IPV6_FIB, NSIM_RESOURCE_IPV6_FIB_RULES
156 };
157 struct net *net = nsim_devlink_net(devlink);
158 int i;
159
160 for (i = 0; i < ARRAY_SIZE(res_ids); ++i) {
161 int err;
162 u64 val;
163
164 err = devlink_resource_size_get(devlink, res_ids[i], &val);
165 if (!err) {
David Ahern7fa76d72018-06-05 08:14:10 -0700166 err = nsim_fib_set_max(net, res_ids[i], val, extack);
David Ahern37923ed2018-03-27 18:22:00 -0700167 if (err)
168 return err;
169 }
170 }
171
172 return 0;
173}
174
175static void nsim_devlink_net_reset(struct net *net)
176{
177 enum nsim_resource_id res_ids[] = {
178 NSIM_RESOURCE_IPV4_FIB, NSIM_RESOURCE_IPV4_FIB_RULES,
179 NSIM_RESOURCE_IPV6_FIB, NSIM_RESOURCE_IPV6_FIB_RULES
180 };
181 int i;
182
183 for (i = 0; i < ARRAY_SIZE(res_ids); ++i) {
David Ahern7fa76d72018-06-05 08:14:10 -0700184 if (nsim_fib_set_max(net, res_ids[i], (u64)-1, NULL)) {
David Ahern37923ed2018-03-27 18:22:00 -0700185 pr_err("Failed to reset limit for resource %u\n",
186 res_ids[i]);
187 }
188 }
189}
190
191static const struct devlink_ops nsim_devlink_ops = {
192 .reload = nsim_devlink_reload,
193};
194
195/* once devlink / namespace issues are sorted out
196 * this needs to be net in which a devlink instance
197 * is to be created. e.g., dev_net(ns->netdev)
198 */
199static struct net *nsim_to_net(struct netdevsim *ns)
200{
201 return &init_net;
202}
203
204void nsim_devlink_teardown(struct netdevsim *ns)
205{
206 if (ns->devlink) {
207 struct net *net = nsim_to_net(ns);
208 bool *reg_devlink = net_generic(net, nsim_devlink_id);
209
210 devlink_unregister(ns->devlink);
211 devlink_free(ns->devlink);
212 ns->devlink = NULL;
213
214 nsim_devlink_net_reset(net);
215 *reg_devlink = true;
216 }
217}
218
David Ahernef817102018-03-30 09:28:51 -0700219int nsim_devlink_setup(struct netdevsim *ns)
David Ahern37923ed2018-03-27 18:22:00 -0700220{
221 struct net *net = nsim_to_net(ns);
222 bool *reg_devlink = net_generic(net, nsim_devlink_id);
223 struct devlink *devlink;
David Ahernef817102018-03-30 09:28:51 -0700224 int err;
David Ahern37923ed2018-03-27 18:22:00 -0700225
226 /* only one device per namespace controls devlink */
227 if (!*reg_devlink) {
228 ns->devlink = NULL;
David Ahernef817102018-03-30 09:28:51 -0700229 return 0;
David Ahern37923ed2018-03-27 18:22:00 -0700230 }
231
232 devlink = devlink_alloc(&nsim_devlink_ops, 0);
233 if (!devlink)
David Ahernef817102018-03-30 09:28:51 -0700234 return -ENOMEM;
David Ahern37923ed2018-03-27 18:22:00 -0700235
236 err = devlink_register(devlink, &ns->dev);
237 if (err)
238 goto err_devlink_free;
239
240 err = devlink_resources_register(devlink);
241 if (err)
242 goto err_dl_unregister;
243
244 ns->devlink = devlink;
245
246 *reg_devlink = false;
247
David Ahernef817102018-03-30 09:28:51 -0700248 return 0;
David Ahern37923ed2018-03-27 18:22:00 -0700249
250err_dl_unregister:
251 devlink_unregister(devlink);
252err_devlink_free:
253 devlink_free(devlink);
David Ahernef817102018-03-30 09:28:51 -0700254
255 return err;
David Ahern37923ed2018-03-27 18:22:00 -0700256}
257
258/* Initialize per network namespace state */
259static int __net_init nsim_devlink_netns_init(struct net *net)
260{
261 bool *reg_devlink = net_generic(net, nsim_devlink_id);
262
263 *reg_devlink = true;
264
265 return 0;
266}
267
Arnd Bergmann87248d32018-04-04 14:12:39 +0200268static struct pernet_operations nsim_devlink_net_ops = {
David Ahern37923ed2018-03-27 18:22:00 -0700269 .init = nsim_devlink_netns_init,
270 .id = &nsim_devlink_id,
271 .size = sizeof(bool),
272};
273
274void nsim_devlink_exit(void)
275{
276 unregister_pernet_subsys(&nsim_devlink_net_ops);
277 nsim_fib_exit();
278}
279
280int nsim_devlink_init(void)
281{
282 int err;
283
284 err = nsim_fib_init();
285 if (err)
286 goto err_out;
287
288 err = register_pernet_subsys(&nsim_devlink_net_ops);
289 if (err)
290 nsim_fib_exit();
291
292err_out:
293 return err;
294}