Loading...
Note: File does not exist in v3.15.
1/*
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(void *priv)
34{
35 struct net *net = priv;
36
37 return nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB, false);
38}
39
40static u64 nsim_ipv4_fib_rules_res_occ_get(void *priv)
41{
42 struct net *net = priv;
43
44 return nsim_fib_get_val(net, NSIM_RESOURCE_IPV4_FIB_RULES, false);
45}
46
47/* IPv6
48 */
49static u64 nsim_ipv6_fib_resource_occ_get(void *priv)
50{
51 struct net *net = priv;
52
53 return nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB, false);
54}
55
56static u64 nsim_ipv6_fib_rules_res_occ_get(void *priv)
57{
58 struct net *net = priv;
59
60 return nsim_fib_get_val(net, NSIM_RESOURCE_IPV6_FIB_RULES, false);
61}
62
63static 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,
78 ¶ms);
79 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,
87 NSIM_RESOURCE_IPV4, ¶ms);
88 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,
96 NSIM_RESOURCE_IPV4, ¶ms);
97 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,
106 ¶ms);
107 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,
115 NSIM_RESOURCE_IPV6, ¶ms);
116 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,
124 NSIM_RESOURCE_IPV6, ¶ms);
125 if (err) {
126 pr_err("Failed to register IPv6 FIB rules resource\n");
127 return err;
128 }
129
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);
146out:
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
218int nsim_devlink_setup(struct netdevsim *ns)
219{
220 struct net *net = nsim_to_net(ns);
221 bool *reg_devlink = net_generic(net, nsim_devlink_id);
222 struct devlink *devlink;
223 int err;
224
225 /* only one device per namespace controls devlink */
226 if (!*reg_devlink) {
227 ns->devlink = NULL;
228 return 0;
229 }
230
231 devlink = devlink_alloc(&nsim_devlink_ops, 0);
232 if (!devlink)
233 return -ENOMEM;
234
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
247 return 0;
248
249err_dl_unregister:
250 devlink_unregister(devlink);
251err_devlink_free:
252 devlink_free(devlink);
253
254 return err;
255}
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
267static struct pernet_operations nsim_devlink_net_ops = {
268 .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}