Skip to content

Commit 37923ed

Browse files
David Aherndavem330
authored andcommitted
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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 2233000 commit 37923ed

File tree

6 files changed

+616
-1
lines changed

6 files changed

+616
-1
lines changed

drivers/net/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,7 @@ source "drivers/net/hyperv/Kconfig"
500500
config NETDEVSIM
501501
tristate "Simulated networking device"
502502
depends on DEBUG_FS
503+
depends on MAY_USE_DEVLINK
503504
help
504505
This driver is a developer testing tool and software model that can
505506
be used to test various control path networking APIs, especially

drivers/net/netdevsim/Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,7 @@ ifeq ($(CONFIG_BPF_SYSCALL),y)
99
netdevsim-objs += \
1010
bpf.o
1111
endif
12+
13+
ifneq ($(CONFIG_NET_DEVLINK),)
14+
netdevsim-objs += devlink.o fib.o
15+
endif

drivers/net/netdevsim/devlink.c

Lines changed: 294 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,294 @@
1+
/*
2+
* Copyright (c) 2018 Cumulus Networks. All rights reserved.
3+
* Copyright (c) 2018 David Ahern <[email protected]>
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+
23+
static unsigned int nsim_devlink_id;
24+
25+
/* place holder until devlink and namespaces is sorted out */
26+
static struct net *nsim_devlink_net(struct devlink *devlink)
27+
{
28+
return &init_net;
29+
}
30+
31+
/* IPv4
32+
*/
33+
static 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+
40+
static struct devlink_resource_ops nsim_ipv4_fib_res_ops = {
41+
.occ_get = nsim_ipv4_fib_resource_occ_get,
42+
};
43+
44+
static 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+
51+
static 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+
*/
57+
static 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+
64+
static struct devlink_resource_ops nsim_ipv6_fib_res_ops = {
65+
.occ_get = nsim_ipv6_fib_resource_occ_get,
66+
};
67+
68+
static 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+
75+
static struct devlink_resource_ops nsim_ipv6_fib_rules_res_ops = {
76+
.occ_get = nsim_ipv6_fib_rules_res_occ_get,
77+
};
78+
79+
static 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+
}
149+
out:
150+
return err;
151+
}
152+
153+
static 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+
177+
static 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+
193+
static 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+
*/
201+
static struct net *nsim_to_net(struct netdevsim *ns)
202+
{
203+
return &init_net;
204+
}
205+
206+
void 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+
221+
void 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+
252+
err_dl_unregister:
253+
devlink_unregister(devlink);
254+
err_devlink_free:
255+
devlink_free(devlink);
256+
}
257+
258+
/* Initialize per network namespace state */
259+
static 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+
268+
static 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+
274+
void nsim_devlink_exit(void)
275+
{
276+
unregister_pernet_subsys(&nsim_devlink_net_ops);
277+
nsim_fib_exit();
278+
}
279+
280+
int 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+
292+
err_out:
293+
return err;
294+
}

0 commit comments

Comments
 (0)