aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/netdevsim/devlink.c
diff options
context:
space:
mode:
authorDavid Ahern <dsa@cumulusnetworks.com>2018-03-27 21:22:00 -0400
committerDavid S. Miller <davem@davemloft.net>2018-03-29 14:10:31 -0400
commit37923ed6b8cea94d7d76038e2f72c57a0b45daab (patch)
tree51418fe5934da050f867b26bf0ee836e14cbc38a /drivers/net/netdevsim/devlink.c
parent2233000cba40ee0784a2d5b5e2b2c38c1159a7ef (diff)
netdevsim: Add simple FIB resource controller via devlink
Add devlink support to netdevsim and use it to implement a simple, profile based resource controller. Only one controller is needed per namespace, so the first netdevsim netdevice in a namespace registers with devlink. If that device is deleted, the resource settings are deleted. The resource controller allows a user to limit the number of IPv4 and IPv6 FIB entries and FIB rules. The resource paths are: /IPv4 /IPv4/fib /IPv4/fib-rules /IPv6 /IPv6/fib /IPv6/fib-rules The IPv4 and IPv6 top level resources are unlimited in size and can not be changed. From there, the number of FIB entries and FIB rule entries are unlimited by default. A user can specify a limit for the fib and fib-rules resources: $ devlink resource set netdevsim/netdevsim0 path /IPv4/fib size 96 $ devlink resource set netdevsim/netdevsim0 path /IPv4/fib-rules size 16 $ devlink resource set netdevsim/netdevsim0 path /IPv6/fib size 64 $ devlink resource set netdevsim/netdevsim0 path /IPv6/fib-rules size 16 $ devlink dev reload netdevsim/netdevsim0 such that the number of rules or routes is limited (96 ipv4 routes in the example above): $ for n in $(seq 1 32); do ip ro add 10.99.$n.0/24 dev eth1; done Error: netdevsim: Exceeded number of supported fib entries. $ devlink resource show netdevsim/netdevsim0 netdevsim/netdevsim0: name IPv4 size unlimited unit entry size_min 0 size_max unlimited size_gran 1 dpipe_tables non resources: name fib size 96 occ 96 unit entry size_min 0 size_max unlimited size_gran 1 dpipe_tables ... With this template in place for resource management, it is fairly trivial to extend and shows one way to implement a simple counter based resource controller typical of network profiles. Currently, devlink only supports initial namespace. Code is in place to adapt netdevsim to a per namespace controller once the network namespace issues are resolved. Signed-off-by: David Ahern <dsa@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/netdevsim/devlink.c')
-rw-r--r--drivers/net/netdevsim/devlink.c294
1 files changed, 294 insertions, 0 deletions
diff --git a/drivers/net/netdevsim/devlink.c b/drivers/net/netdevsim/devlink.c
new file mode 100644
index 000000000000..bbdcf064ba10
--- /dev/null
+++ b/drivers/net/netdevsim/devlink.c
@@ -0,0 +1,294 @@
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(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
221void nsim_devlink_setup(struct netdevsim *ns)
222{
223 struct net *net = nsim_to_net(ns);
224 bool *reg_devlink = net_generic(net, nsim_devlink_id);
225 struct devlink *devlink;
226 int err = -ENOMEM;
227
228 /* only one device per namespace controls devlink */
229 if (!*reg_devlink) {
230 ns->devlink = NULL;
231 return;
232 }
233
234 devlink = devlink_alloc(&nsim_devlink_ops, 0);
235 if (!devlink)
236 return;
237
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
250 return;
251
252err_dl_unregister:
253 devlink_unregister(devlink);
254err_devlink_free:
255 devlink_free(devlink);
256}
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
268static struct pernet_operations nsim_devlink_net_ops __net_initdata = {
269 .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}