blob: bef7db5d129a55c31b6d0f2a5094c7b61b61b1d5 [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
150static int nsim_devlink_reload(struct devlink *devlink)
151{
152 enum nsim_resource_id res_ids[] = {
153 NSIM_RESOURCE_IPV4_FIB, NSIM_RESOURCE_IPV4_FIB_RULES,
154 NSIM_RESOURCE_IPV6_FIB, NSIM_RESOURCE_IPV6_FIB_RULES
155 };
156 struct net *net = nsim_devlink_net(devlink);
157 int i;
158
159 for (i = 0; i < ARRAY_SIZE(res_ids); ++i) {
160 int err;
161 u64 val;
162
163 err = devlink_resource_size_get(devlink, res_ids[i], &val);
164 if (!err) {
165 err = nsim_fib_set_max(net, res_ids[i], val);
166 if (err)
167 return err;
168 }
169 }
170
171 return 0;
172}
173
174static void nsim_devlink_net_reset(struct net *net)
175{
176 enum nsim_resource_id res_ids[] = {
177 NSIM_RESOURCE_IPV4_FIB, NSIM_RESOURCE_IPV4_FIB_RULES,
178 NSIM_RESOURCE_IPV6_FIB, NSIM_RESOURCE_IPV6_FIB_RULES
179 };
180 int i;
181
182 for (i = 0; i < ARRAY_SIZE(res_ids); ++i) {
183 if (nsim_fib_set_max(net, res_ids[i], (u64)-1)) {
184 pr_err("Failed to reset limit for resource %u\n",
185 res_ids[i]);
186 }
187 }
188}
189
190static const struct devlink_ops nsim_devlink_ops = {
191 .reload = nsim_devlink_reload,
192};
193
194/* once devlink / namespace issues are sorted out
195 * this needs to be net in which a devlink instance
196 * is to be created. e.g., dev_net(ns->netdev)
197 */
198static struct net *nsim_to_net(struct netdevsim *ns)
199{
200 return &init_net;
201}
202
203void nsim_devlink_teardown(struct netdevsim *ns)
204{
205 if (ns->devlink) {
206 struct net *net = nsim_to_net(ns);
207 bool *reg_devlink = net_generic(net, nsim_devlink_id);
208
209 devlink_unregister(ns->devlink);
210 devlink_free(ns->devlink);
211 ns->devlink = NULL;
212
213 nsim_devlink_net_reset(net);
214 *reg_devlink = true;
215 }
216}
217
David Ahernef817102018-03-30 09:28:51 -0700218int nsim_devlink_setup(struct netdevsim *ns)
David Ahern37923ed2018-03-27 18:22:00 -0700219{
220 struct net *net = nsim_to_net(ns);
221 bool *reg_devlink = net_generic(net, nsim_devlink_id);
222 struct devlink *devlink;
David Ahernef817102018-03-30 09:28:51 -0700223 int err;
David Ahern37923ed2018-03-27 18:22:00 -0700224
225 /* only one device per namespace controls devlink */
226 if (!*reg_devlink) {
227 ns->devlink = NULL;
David Ahernef817102018-03-30 09:28:51 -0700228 return 0;
David Ahern37923ed2018-03-27 18:22:00 -0700229 }
230
231 devlink = devlink_alloc(&nsim_devlink_ops, 0);
232 if (!devlink)
David Ahernef817102018-03-30 09:28:51 -0700233 return -ENOMEM;
David Ahern37923ed2018-03-27 18:22:00 -0700234
235 err = devlink_register(devlink, &ns->dev);
236 if (err)
237 goto err_devlink_free;
238
239 err = devlink_resources_register(devlink);
240 if (err)
241 goto err_dl_unregister;
242
243 ns->devlink = devlink;
244
245 *reg_devlink = false;
246
David Ahernef817102018-03-30 09:28:51 -0700247 return 0;
David Ahern37923ed2018-03-27 18:22:00 -0700248
249err_dl_unregister:
250 devlink_unregister(devlink);
251err_devlink_free:
252 devlink_free(devlink);
David Ahernef817102018-03-30 09:28:51 -0700253
254 return err;
David Ahern37923ed2018-03-27 18:22:00 -0700255}
256
257/* Initialize per network namespace state */
258static int __net_init nsim_devlink_netns_init(struct net *net)
259{
260 bool *reg_devlink = net_generic(net, nsim_devlink_id);
261
262 *reg_devlink = true;
263
264 return 0;
265}
266
Arnd Bergmann87248d32018-04-04 14:12:39 +0200267static struct pernet_operations nsim_devlink_net_ops = {
David Ahern37923ed2018-03-27 18:22:00 -0700268 .init = nsim_devlink_netns_init,
269 .id = &nsim_devlink_id,
270 .size = sizeof(bool),
271};
272
273void nsim_devlink_exit(void)
274{
275 unregister_pernet_subsys(&nsim_devlink_net_ops);
276 nsim_fib_exit();
277}
278
279int nsim_devlink_init(void)
280{
281 int err;
282
283 err = nsim_fib_init();
284 if (err)
285 goto err_out;
286
287 err = register_pernet_subsys(&nsim_devlink_net_ops);
288 if (err)
289 nsim_fib_exit();
290
291err_out:
292 return err;
293}