Skip to content

Commit 82c93a8

Browse files
jpirkodavem330
authored andcommitted
netdevsim: implement couple of testing devlink health reporters
Implement "empty" and "dummy" reporters. The first one is really simple and does nothing. The other one has debugfs files to trigger breakage and it is able to do recovery. The ops also implement dummy fmsg content. Signed-off-by: Jiri Pirko <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent e7a9810 commit 82c93a8

File tree

4 files changed

+354
-3
lines changed

4 files changed

+354
-3
lines changed

drivers/net/netdevsim/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
obj-$(CONFIG_NETDEVSIM) += netdevsim.o
44

55
netdevsim-objs := \
6-
netdev.o dev.o fib.o bus.o
6+
netdev.o dev.o fib.o bus.o health.o
77

88
ifeq ($(CONFIG_BPF_SYSCALL),y)
99
netdevsim-objs += \

drivers/net/netdevsim/dev.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -730,12 +730,18 @@ static int nsim_dev_reload_create(struct nsim_dev *nsim_dev,
730730
if (err)
731731
goto err_dummy_region_exit;
732732

733-
err = nsim_dev_port_add_all(nsim_dev, nsim_bus_dev->port_count);
733+
err = nsim_dev_health_init(nsim_dev, devlink);
734734
if (err)
735735
goto err_traps_exit;
736736

737+
err = nsim_dev_port_add_all(nsim_dev, nsim_bus_dev->port_count);
738+
if (err)
739+
goto err_health_exit;
740+
737741
return 0;
738742

743+
err_health_exit:
744+
nsim_dev_health_exit(nsim_dev);
739745
err_traps_exit:
740746
nsim_dev_traps_exit(devlink);
741747
err_dummy_region_exit:
@@ -797,10 +803,14 @@ static struct nsim_dev *nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev)
797803
if (err)
798804
goto err_traps_exit;
799805

800-
err = nsim_bpf_dev_init(nsim_dev);
806+
err = nsim_dev_health_init(nsim_dev, devlink);
801807
if (err)
802808
goto err_debugfs_exit;
803809

810+
err = nsim_bpf_dev_init(nsim_dev);
811+
if (err)
812+
goto err_health_exit;
813+
804814
err = nsim_dev_port_add_all(nsim_dev, nsim_bus_dev->port_count);
805815
if (err)
806816
goto err_bpf_dev_exit;
@@ -810,6 +820,8 @@ static struct nsim_dev *nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev)
810820

811821
err_bpf_dev_exit:
812822
nsim_bpf_dev_exit(nsim_dev);
823+
err_health_exit:
824+
nsim_dev_health_exit(nsim_dev);
813825
err_debugfs_exit:
814826
nsim_dev_debugfs_exit(nsim_dev);
815827
err_traps_exit:
@@ -837,6 +849,7 @@ static void nsim_dev_reload_destroy(struct nsim_dev *nsim_dev)
837849
if (devlink_is_reload_failed(devlink))
838850
return;
839851
nsim_dev_port_del_all(nsim_dev);
852+
nsim_dev_health_exit(nsim_dev);
840853
nsim_dev_traps_exit(devlink);
841854
nsim_dev_dummy_region_exit(nsim_dev);
842855
mutex_destroy(&nsim_dev->port_list_lock);

drivers/net/netdevsim/health.c

Lines changed: 325 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,325 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (c) 2019 Mellanox Technologies. All rights reserved */
3+
4+
#include <linux/debugfs.h>
5+
#include <linux/err.h>
6+
#include <linux/kernel.h>
7+
#include <linux/slab.h>
8+
9+
#include "netdevsim.h"
10+
11+
static int
12+
nsim_dev_empty_reporter_dump(struct devlink_health_reporter *reporter,
13+
struct devlink_fmsg *fmsg, void *priv_ctx,
14+
struct netlink_ext_ack *extack)
15+
{
16+
return 0;
17+
}
18+
19+
static int
20+
nsim_dev_empty_reporter_diagnose(struct devlink_health_reporter *reporter,
21+
struct devlink_fmsg *fmsg,
22+
struct netlink_ext_ack *extack)
23+
{
24+
return 0;
25+
}
26+
27+
static const
28+
struct devlink_health_reporter_ops nsim_dev_empty_reporter_ops = {
29+
.name = "empty",
30+
.dump = nsim_dev_empty_reporter_dump,
31+
.diagnose = nsim_dev_empty_reporter_diagnose,
32+
};
33+
34+
struct nsim_dev_dummy_reporter_ctx {
35+
char *break_msg;
36+
};
37+
38+
static int
39+
nsim_dev_dummy_reporter_recover(struct devlink_health_reporter *reporter,
40+
void *priv_ctx,
41+
struct netlink_ext_ack *extack)
42+
{
43+
struct nsim_dev_health *health = devlink_health_reporter_priv(reporter);
44+
struct nsim_dev_dummy_reporter_ctx *ctx = priv_ctx;
45+
46+
if (health->fail_recover) {
47+
/* For testing purposes, user set debugfs fail_recover
48+
* value to true. Fail right away.
49+
*/
50+
NL_SET_ERR_MSG_MOD(extack, "User setup the recover to fail for testing purposes");
51+
return -EINVAL;
52+
}
53+
if (ctx) {
54+
kfree(health->recovered_break_msg);
55+
health->recovered_break_msg = kstrdup(ctx->break_msg,
56+
GFP_KERNEL);
57+
if (!health->recovered_break_msg)
58+
return -ENOMEM;
59+
}
60+
return 0;
61+
}
62+
63+
static int nsim_dev_dummy_fmsg_put(struct devlink_fmsg *fmsg, u32 binary_len)
64+
{
65+
char *binary;
66+
int err;
67+
int i;
68+
69+
err = devlink_fmsg_bool_pair_put(fmsg, "test_bool", true);
70+
if (err)
71+
return err;
72+
err = devlink_fmsg_u8_pair_put(fmsg, "test_u8", 1);
73+
if (err)
74+
return err;
75+
err = devlink_fmsg_u32_pair_put(fmsg, "test_u32", 3);
76+
if (err)
77+
return err;
78+
err = devlink_fmsg_u64_pair_put(fmsg, "test_u64", 4);
79+
if (err)
80+
return err;
81+
err = devlink_fmsg_string_pair_put(fmsg, "test_string", "somestring");
82+
if (err)
83+
return err;
84+
85+
err = devlink_fmsg_arr_pair_nest_start(fmsg, "test_binary");
86+
if (err)
87+
return err;
88+
binary = kmalloc(binary_len, GFP_KERNEL);
89+
if (!binary)
90+
return -ENOMEM;
91+
get_random_bytes(binary, binary_len);
92+
err = devlink_fmsg_binary_put(fmsg, binary, binary_len);
93+
kfree(binary);
94+
if (err)
95+
return err;
96+
err = devlink_fmsg_arr_pair_nest_end(fmsg);
97+
if (err)
98+
return err;
99+
100+
err = devlink_fmsg_pair_nest_start(fmsg, "test_nest");
101+
if (err)
102+
return err;
103+
err = devlink_fmsg_obj_nest_start(fmsg);
104+
if (err)
105+
return err;
106+
err = devlink_fmsg_bool_pair_put(fmsg, "nested_test_bool", false);
107+
if (err)
108+
return err;
109+
err = devlink_fmsg_u8_pair_put(fmsg, "nested_test_u8", false);
110+
if (err)
111+
return err;
112+
err = devlink_fmsg_obj_nest_end(fmsg);
113+
if (err)
114+
return err;
115+
err = devlink_fmsg_pair_nest_end(fmsg);
116+
if (err)
117+
return err;
118+
119+
err = devlink_fmsg_arr_pair_nest_start(fmsg, "test_bool_array");
120+
if (err)
121+
return err;
122+
for (i = 0; i < 10; i++) {
123+
err = devlink_fmsg_bool_put(fmsg, true);
124+
if (err)
125+
return err;
126+
}
127+
err = devlink_fmsg_arr_pair_nest_end(fmsg);
128+
if (err)
129+
return err;
130+
131+
err = devlink_fmsg_arr_pair_nest_start(fmsg, "test_u8_array");
132+
if (err)
133+
return err;
134+
for (i = 0; i < 10; i++) {
135+
err = devlink_fmsg_u8_put(fmsg, i);
136+
if (err)
137+
return err;
138+
}
139+
err = devlink_fmsg_arr_pair_nest_end(fmsg);
140+
if (err)
141+
return err;
142+
143+
err = devlink_fmsg_arr_pair_nest_start(fmsg, "test_u32_array");
144+
if (err)
145+
return err;
146+
for (i = 0; i < 10; i++) {
147+
err = devlink_fmsg_u32_put(fmsg, i);
148+
if (err)
149+
return err;
150+
}
151+
err = devlink_fmsg_arr_pair_nest_end(fmsg);
152+
if (err)
153+
return err;
154+
155+
err = devlink_fmsg_arr_pair_nest_start(fmsg, "test_u64_array");
156+
if (err)
157+
return err;
158+
for (i = 0; i < 10; i++) {
159+
err = devlink_fmsg_u64_put(fmsg, i);
160+
if (err)
161+
return err;
162+
}
163+
err = devlink_fmsg_arr_pair_nest_end(fmsg);
164+
if (err)
165+
return err;
166+
167+
err = devlink_fmsg_arr_pair_nest_start(fmsg, "test_array_of_objects");
168+
if (err)
169+
return err;
170+
for (i = 0; i < 10; i++) {
171+
err = devlink_fmsg_obj_nest_start(fmsg);
172+
if (err)
173+
return err;
174+
err = devlink_fmsg_bool_pair_put(fmsg,
175+
"in_array_nested_test_bool",
176+
false);
177+
if (err)
178+
return err;
179+
err = devlink_fmsg_u8_pair_put(fmsg,
180+
"in_array_nested_test_u8",
181+
i);
182+
if (err)
183+
return err;
184+
err = devlink_fmsg_obj_nest_end(fmsg);
185+
if (err)
186+
return err;
187+
}
188+
return devlink_fmsg_arr_pair_nest_end(fmsg);
189+
}
190+
191+
static int
192+
nsim_dev_dummy_reporter_dump(struct devlink_health_reporter *reporter,
193+
struct devlink_fmsg *fmsg, void *priv_ctx,
194+
struct netlink_ext_ack *extack)
195+
{
196+
struct nsim_dev_health *health = devlink_health_reporter_priv(reporter);
197+
struct nsim_dev_dummy_reporter_ctx *ctx = priv_ctx;
198+
int err;
199+
200+
if (ctx) {
201+
err = devlink_fmsg_string_pair_put(fmsg, "break_message",
202+
ctx->break_msg);
203+
if (err)
204+
return err;
205+
}
206+
return nsim_dev_dummy_fmsg_put(fmsg, health->binary_len);
207+
}
208+
209+
static int
210+
nsim_dev_dummy_reporter_diagnose(struct devlink_health_reporter *reporter,
211+
struct devlink_fmsg *fmsg,
212+
struct netlink_ext_ack *extack)
213+
{
214+
struct nsim_dev_health *health = devlink_health_reporter_priv(reporter);
215+
int err;
216+
217+
if (health->recovered_break_msg) {
218+
err = devlink_fmsg_string_pair_put(fmsg,
219+
"recovered_break_message",
220+
health->recovered_break_msg);
221+
if (err)
222+
return err;
223+
}
224+
return nsim_dev_dummy_fmsg_put(fmsg, health->binary_len);
225+
}
226+
227+
static const
228+
struct devlink_health_reporter_ops nsim_dev_dummy_reporter_ops = {
229+
.name = "dummy",
230+
.recover = nsim_dev_dummy_reporter_recover,
231+
.dump = nsim_dev_dummy_reporter_dump,
232+
.diagnose = nsim_dev_dummy_reporter_diagnose,
233+
};
234+
235+
static ssize_t nsim_dev_health_break_write(struct file *file,
236+
const char __user *data,
237+
size_t count, loff_t *ppos)
238+
{
239+
struct nsim_dev_health *health = file->private_data;
240+
struct nsim_dev_dummy_reporter_ctx ctx;
241+
char *break_msg;
242+
int err;
243+
244+
break_msg = kmalloc(count + 1, GFP_KERNEL);
245+
if (!break_msg)
246+
return -ENOMEM;
247+
248+
if (copy_from_user(break_msg, data, count)) {
249+
err = -EFAULT;
250+
goto out;
251+
}
252+
break_msg[count] = '\0';
253+
if (break_msg[count - 1] == '\n')
254+
break_msg[count - 1] = '\0';
255+
256+
ctx.break_msg = break_msg;
257+
err = devlink_health_report(health->dummy_reporter, break_msg, &ctx);
258+
if (err)
259+
goto out;
260+
261+
out:
262+
kfree(break_msg);
263+
return err ?: count;
264+
}
265+
266+
static const struct file_operations nsim_dev_health_break_fops = {
267+
.open = simple_open,
268+
.write = nsim_dev_health_break_write,
269+
.llseek = generic_file_llseek,
270+
};
271+
272+
int nsim_dev_health_init(struct nsim_dev *nsim_dev, struct devlink *devlink)
273+
{
274+
struct nsim_dev_health *health = &nsim_dev->health;
275+
int err;
276+
277+
health->empty_reporter =
278+
devlink_health_reporter_create(devlink,
279+
&nsim_dev_empty_reporter_ops,
280+
0, false, health);
281+
if (IS_ERR(health->empty_reporter))
282+
return PTR_ERR(health->empty_reporter);
283+
284+
health->dummy_reporter =
285+
devlink_health_reporter_create(devlink,
286+
&nsim_dev_dummy_reporter_ops,
287+
0, false, health);
288+
if (IS_ERR(health->dummy_reporter)) {
289+
err = PTR_ERR(health->dummy_reporter);
290+
goto err_empty_reporter_destroy;
291+
}
292+
293+
health->ddir = debugfs_create_dir("health", nsim_dev->ddir);
294+
if (IS_ERR_OR_NULL(health->ddir)) {
295+
err = PTR_ERR_OR_ZERO(health->ddir) ?: -EINVAL;
296+
goto err_dummy_reporter_destroy;
297+
}
298+
299+
health->recovered_break_msg = NULL;
300+
debugfs_create_file("break_health", 0200, health->ddir, health,
301+
&nsim_dev_health_break_fops);
302+
health->binary_len = 16;
303+
debugfs_create_u32("binary_len", 0600, health->ddir,
304+
&health->binary_len);
305+
health->fail_recover = false;
306+
debugfs_create_bool("fail_recover", 0600, health->ddir,
307+
&health->fail_recover);
308+
return 0;
309+
310+
err_dummy_reporter_destroy:
311+
devlink_health_reporter_destroy(health->dummy_reporter);
312+
err_empty_reporter_destroy:
313+
devlink_health_reporter_destroy(health->empty_reporter);
314+
return err;
315+
}
316+
317+
void nsim_dev_health_exit(struct nsim_dev *nsim_dev)
318+
{
319+
struct nsim_dev_health *health = &nsim_dev->health;
320+
321+
debugfs_remove_recursive(health->ddir);
322+
kfree(health->recovered_break_msg);
323+
devlink_health_reporter_destroy(health->dummy_reporter);
324+
devlink_health_reporter_destroy(health->empty_reporter);
325+
}

0 commit comments

Comments
 (0)