Message ID | 20191009110445.23237-4-jiri@resnulli.us |
---|---|
State | Changes Requested |
Delegated to: | David Miller |
Headers | show |
Series | netdevsim: add devlink health reporters support | expand |
On Wed, 9 Oct 2019 13:04:44 +0200, Jiri Pirko wrote: > From: Jiri Pirko <jiri@mellanox.com> > > 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 <jiri@mellanox.com> > diff --git a/drivers/net/netdevsim/health.c b/drivers/net/netdevsim/health.c > new file mode 100644 > index 000000000000..088ae8fd89fc > --- /dev/null > +++ b/drivers/net/netdevsim/health.c > +static int > +nsim_dev_dummy_reporter_recover(struct devlink_health_reporter *reporter, > + void *priv_ctx, > + struct netlink_ext_ack *extack) > +{ > + struct nsim_dev_health *health = devlink_health_reporter_priv(reporter); > + struct nsim_dev_dummy_reporter_ctx *ctx = priv_ctx; > + > + if (health->fail_recover) { > + /* For testing purposes, user set debugfs fail_recover > + * value to true. Fail right away. > + */ > + NL_SET_ERR_MSG_MOD(extack, "User setup the recover to fail for testing purposes"); > + return -EINVAL; > + } > + if (ctx) { > + health->recovered_break_msg = kstrdup(ctx->break_msg, Can't there already be a message there? wouldn't this leak it? > + GFP_KERNEL); > + if (!health->recovered_break_msg) > + return -ENOMEM; > + } > + return 0; > +} > +static ssize_t nsim_dev_health_break_write(struct file *file, > + const char __user *data, > + size_t count, loff_t *ppos) > +{ > + struct nsim_dev_health *health = file->private_data; > + struct nsim_dev_dummy_reporter_ctx ctx; > + char *break_msg; > + int err; > + > + break_msg = kmalloc(count + 1, GFP_KERNEL); > + if (!break_msg) > + return -ENOMEM; > + > + if (copy_from_user(break_msg, data, count)) { > + err = -EFAULT; > + goto out; > + } > + break_msg[count] = '\0'; > + if (break_msg[count - 1] == '\n') > + break_msg[count - 1] = '\0'; > + > + ctx.break_msg = break_msg; > + err = devlink_health_report(health->dummy_reporter, break_msg, &ctx); > + if (err) > + goto out; > + > +out: > + kfree(break_msg); > + return err ? err : count; nit: ?: works here, like you used below > +} > + > +static const struct file_operations nsim_dev_health_break_fops = { > + .open = simple_open, > + .write = nsim_dev_health_break_write, > + .llseek = generic_file_llseek, > +}; > + > +int nsim_dev_health_init(struct nsim_dev *nsim_dev, struct devlink *devlink) > +{ > + struct nsim_dev_health *health = &nsim_dev->health; > + int err; > + > + health->empty_reporter = > + devlink_health_reporter_create(devlink, > + &nsim_dev_empty_reporter_ops, > + 0, false, health); > + if (IS_ERR(health->empty_reporter)) > + return PTR_ERR(health->empty_reporter); > + > + health->dummy_reporter = > + devlink_health_reporter_create(devlink, > + &nsim_dev_dummy_reporter_ops, > + 0, false, health); > + if (IS_ERR(health->dummy_reporter)) { > + err = PTR_ERR(health->dummy_reporter); > + goto err_empty_reporter_destroy; > + } > + > + health->ddir = debugfs_create_dir("health", nsim_dev->ddir); > + if (IS_ERR_OR_NULL(health->ddir)) > + return PTR_ERR_OR_ZERO(health->ddir) ?: -EINVAL; goto err_dummy_reporter_destroy? > + health->recovered_break_msg = NULL; > + debugfs_create_file("break_health", 0200, health->ddir, health, > + &nsim_dev_health_break_fops); > + health->binary_len = 16; > + debugfs_create_u32("binary_len", 0600, health->ddir, > + &health->binary_len); > + health->fail_recover = false; > + debugfs_create_bool("fail_recover", 0600, health->ddir, > + &health->fail_recover); > + return 0; > + > +err_empty_reporter_destroy: > + devlink_health_reporter_destroy(health->empty_reporter); > + return err; > +} > + > +void nsim_dev_health_exit(struct nsim_dev *nsim_dev) > +{ > + struct nsim_dev_health *health = &nsim_dev->health; > + > + debugfs_remove_recursive(health->ddir); > + kfree(health->recovered_break_msg); > + devlink_health_reporter_destroy(health->dummy_reporter); > + devlink_health_reporter_destroy(health->empty_reporter); > +} > diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h > index 24358385d869..657cbae50293 100644 > --- a/drivers/net/netdevsim/netdevsim.h > +++ b/drivers/net/netdevsim/netdevsim.h > @@ -18,6 +18,7 @@ > #include <linux/list.h> > #include <linux/netdevice.h> > #include <linux/u64_stats_sync.h> > +#include <linux/debugfs.h> I don't think this include is needed? Forward declaration of struct dentry, should be sufficient, if needed, no? > #include <net/devlink.h> > #include <net/xdp.h> > > @@ -134,6 +135,18 @@ enum nsim_resource_id { > NSIM_RESOURCE_IPV6_FIB_RULES, > }; > > +struct nsim_dev_health { > + struct devlink_health_reporter *empty_reporter; > + struct devlink_health_reporter *dummy_reporter; > + struct dentry *ddir; > + char *recovered_break_msg; > + u32 binary_len; > + bool fail_recover; > +}; > + > +int nsim_dev_health_init(struct nsim_dev *nsim_dev, struct devlink *devlink); > +void nsim_dev_health_exit(struct nsim_dev *nsim_dev); > + > struct nsim_dev_port { > struct list_head list; > struct devlink_port devlink_port; > @@ -164,6 +177,7 @@ struct nsim_dev { > bool dont_allow_reload; > bool fail_reload; > struct devlink_region *dummy_region; > + struct nsim_dev_health health; > }; > > static inline struct net *nsim_dev_net(struct nsim_dev *nsim_dev)
Thu, Oct 10, 2019 at 05:53:51AM CEST, jakub.kicinski@netronome.com wrote: >On Wed, 9 Oct 2019 13:04:44 +0200, Jiri Pirko wrote: >> From: Jiri Pirko <jiri@mellanox.com> >> >> 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 <jiri@mellanox.com> > >> diff --git a/drivers/net/netdevsim/health.c b/drivers/net/netdevsim/health.c >> new file mode 100644 >> index 000000000000..088ae8fd89fc >> --- /dev/null >> +++ b/drivers/net/netdevsim/health.c > >> +static int >> +nsim_dev_dummy_reporter_recover(struct devlink_health_reporter *reporter, >> + void *priv_ctx, >> + struct netlink_ext_ack *extack) >> +{ >> + struct nsim_dev_health *health = devlink_health_reporter_priv(reporter); >> + struct nsim_dev_dummy_reporter_ctx *ctx = priv_ctx; >> + >> + if (health->fail_recover) { >> + /* For testing purposes, user set debugfs fail_recover >> + * value to true. Fail right away. >> + */ >> + NL_SET_ERR_MSG_MOD(extack, "User setup the recover to fail for testing purposes"); >> + return -EINVAL; >> + } >> + if (ctx) { >> + health->recovered_break_msg = kstrdup(ctx->break_msg, > >Can't there already be a message there? wouldn't this leak it? It would. Will fix. > >> + GFP_KERNEL); >> + if (!health->recovered_break_msg) >> + return -ENOMEM; >> + } >> + return 0; >> +} > >> +static ssize_t nsim_dev_health_break_write(struct file *file, >> + const char __user *data, >> + size_t count, loff_t *ppos) >> +{ >> + struct nsim_dev_health *health = file->private_data; >> + struct nsim_dev_dummy_reporter_ctx ctx; >> + char *break_msg; >> + int err; >> + >> + break_msg = kmalloc(count + 1, GFP_KERNEL); >> + if (!break_msg) >> + return -ENOMEM; >> + >> + if (copy_from_user(break_msg, data, count)) { >> + err = -EFAULT; >> + goto out; >> + } >> + break_msg[count] = '\0'; >> + if (break_msg[count - 1] == '\n') >> + break_msg[count - 1] = '\0'; >> + >> + ctx.break_msg = break_msg; >> + err = devlink_health_report(health->dummy_reporter, break_msg, &ctx); >> + if (err) >> + goto out; >> + >> +out: >> + kfree(break_msg); >> + return err ? err : count; > >nit: ?: works here, like you used below Ok. > >> +} >> + >> +static const struct file_operations nsim_dev_health_break_fops = { >> + .open = simple_open, >> + .write = nsim_dev_health_break_write, >> + .llseek = generic_file_llseek, >> +}; >> + >> +int nsim_dev_health_init(struct nsim_dev *nsim_dev, struct devlink *devlink) >> +{ >> + struct nsim_dev_health *health = &nsim_dev->health; >> + int err; >> + >> + health->empty_reporter = >> + devlink_health_reporter_create(devlink, >> + &nsim_dev_empty_reporter_ops, >> + 0, false, health); >> + if (IS_ERR(health->empty_reporter)) >> + return PTR_ERR(health->empty_reporter); >> + >> + health->dummy_reporter = >> + devlink_health_reporter_create(devlink, >> + &nsim_dev_dummy_reporter_ops, >> + 0, false, health); >> + if (IS_ERR(health->dummy_reporter)) { >> + err = PTR_ERR(health->dummy_reporter); >> + goto err_empty_reporter_destroy; >> + } >> + >> + health->ddir = debugfs_create_dir("health", nsim_dev->ddir); >> + if (IS_ERR_OR_NULL(health->ddir)) >> + return PTR_ERR_OR_ZERO(health->ddir) ?: -EINVAL; > >goto err_dummy_reporter_destroy? Right. > >> + health->recovered_break_msg = NULL; >> + debugfs_create_file("break_health", 0200, health->ddir, health, >> + &nsim_dev_health_break_fops); >> + health->binary_len = 16; >> + debugfs_create_u32("binary_len", 0600, health->ddir, >> + &health->binary_len); >> + health->fail_recover = false; >> + debugfs_create_bool("fail_recover", 0600, health->ddir, >> + &health->fail_recover); >> + return 0; >> + >> +err_empty_reporter_destroy: >> + devlink_health_reporter_destroy(health->empty_reporter); >> + return err; >> +} >> + >> +void nsim_dev_health_exit(struct nsim_dev *nsim_dev) >> +{ >> + struct nsim_dev_health *health = &nsim_dev->health; >> + >> + debugfs_remove_recursive(health->ddir); >> + kfree(health->recovered_break_msg); >> + devlink_health_reporter_destroy(health->dummy_reporter); >> + devlink_health_reporter_destroy(health->empty_reporter); >> +} >> diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h >> index 24358385d869..657cbae50293 100644 >> --- a/drivers/net/netdevsim/netdevsim.h >> +++ b/drivers/net/netdevsim/netdevsim.h >> @@ -18,6 +18,7 @@ >> #include <linux/list.h> >> #include <linux/netdevice.h> >> #include <linux/u64_stats_sync.h> >> +#include <linux/debugfs.h> > >I don't think this include is needed? Forward declaration of >struct dentry, should be sufficient, if needed, no? Right. > >> #include <net/devlink.h> >> #include <net/xdp.h> >> >> @@ -134,6 +135,18 @@ enum nsim_resource_id { >> NSIM_RESOURCE_IPV6_FIB_RULES, >> }; >> >> +struct nsim_dev_health { >> + struct devlink_health_reporter *empty_reporter; >> + struct devlink_health_reporter *dummy_reporter; >> + struct dentry *ddir; >> + char *recovered_break_msg; >> + u32 binary_len; >> + bool fail_recover; >> +}; >> + >> +int nsim_dev_health_init(struct nsim_dev *nsim_dev, struct devlink *devlink); >> +void nsim_dev_health_exit(struct nsim_dev *nsim_dev); >> + >> struct nsim_dev_port { >> struct list_head list; >> struct devlink_port devlink_port; >> @@ -164,6 +177,7 @@ struct nsim_dev { >> bool dont_allow_reload; >> bool fail_reload; >> struct devlink_region *dummy_region; >> + struct nsim_dev_health health; >> }; >> >> static inline struct net *nsim_dev_net(struct nsim_dev *nsim_dev) >
diff --git a/drivers/net/netdevsim/Makefile b/drivers/net/netdevsim/Makefile index 09f1315d2f2a..f4d8f62f28c2 100644 --- a/drivers/net/netdevsim/Makefile +++ b/drivers/net/netdevsim/Makefile @@ -3,7 +3,7 @@ obj-$(CONFIG_NETDEVSIM) += netdevsim.o netdevsim-objs := \ - netdev.o dev.o fib.o bus.o + netdev.o dev.o fib.o bus.o health.o ifeq ($(CONFIG_BPF_SYSCALL),y) netdevsim-objs += \ diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c index e47fa7b6ca7c..468e157a7cb1 100644 --- a/drivers/net/netdevsim/dev.c +++ b/drivers/net/netdevsim/dev.c @@ -730,12 +730,18 @@ static int nsim_dev_reload_create(struct nsim_dev *nsim_dev, if (err) goto err_dummy_region_exit; - err = nsim_dev_port_add_all(nsim_dev, nsim_bus_dev->port_count); + err = nsim_dev_health_init(nsim_dev, devlink); if (err) goto err_traps_exit; + err = nsim_dev_port_add_all(nsim_dev, nsim_bus_dev->port_count); + if (err) + goto err_health_exit; + return 0; +err_health_exit: + nsim_dev_health_exit(nsim_dev); err_traps_exit: nsim_dev_traps_exit(devlink); err_dummy_region_exit: @@ -797,10 +803,14 @@ static struct nsim_dev *nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev) if (err) goto err_traps_exit; - err = nsim_bpf_dev_init(nsim_dev); + err = nsim_dev_health_init(nsim_dev, devlink); if (err) goto err_debugfs_exit; + err = nsim_bpf_dev_init(nsim_dev); + if (err) + goto err_health_exit; + err = nsim_dev_port_add_all(nsim_dev, nsim_bus_dev->port_count); if (err) goto err_bpf_dev_exit; @@ -810,6 +820,8 @@ static struct nsim_dev *nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev) err_bpf_dev_exit: nsim_bpf_dev_exit(nsim_dev); +err_health_exit: + nsim_dev_health_exit(nsim_dev); err_debugfs_exit: nsim_dev_debugfs_exit(nsim_dev); err_traps_exit: @@ -837,6 +849,7 @@ static void nsim_dev_reload_destroy(struct nsim_dev *nsim_dev) if (devlink_is_reload_failed(devlink)) return; nsim_dev_port_del_all(nsim_dev); + nsim_dev_health_exit(nsim_dev); nsim_dev_traps_exit(devlink); nsim_dev_dummy_region_exit(nsim_dev); mutex_destroy(&nsim_dev->port_list_lock); diff --git a/drivers/net/netdevsim/health.c b/drivers/net/netdevsim/health.c new file mode 100644 index 000000000000..088ae8fd89fc --- /dev/null +++ b/drivers/net/netdevsim/health.c @@ -0,0 +1,315 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2019 Mellanox Technologies. All rights reserved */ + +#include <linux/debugfs.h> +#include <linux/err.h> +#include <linux/kernel.h> +#include <linux/slab.h> + +#include "netdevsim.h" + +static int +nsim_dev_empty_reporter_dump(struct devlink_health_reporter *reporter, + struct devlink_fmsg *fmsg, void *priv_ctx, + struct netlink_ext_ack *extack) +{ + return 0; +} + +static int +nsim_dev_empty_reporter_diagnose(struct devlink_health_reporter *reporter, + struct devlink_fmsg *fmsg, + struct netlink_ext_ack *extack) +{ + return 0; +} + +static const +struct devlink_health_reporter_ops nsim_dev_empty_reporter_ops = { + .name = "empty", + .dump = nsim_dev_empty_reporter_dump, + .diagnose = nsim_dev_empty_reporter_diagnose, +}; + +struct nsim_dev_dummy_reporter_ctx { + char *break_msg; +}; + +static int +nsim_dev_dummy_reporter_recover(struct devlink_health_reporter *reporter, + void *priv_ctx, + struct netlink_ext_ack *extack) +{ + struct nsim_dev_health *health = devlink_health_reporter_priv(reporter); + struct nsim_dev_dummy_reporter_ctx *ctx = priv_ctx; + + if (health->fail_recover) { + /* For testing purposes, user set debugfs fail_recover + * value to true. Fail right away. + */ + NL_SET_ERR_MSG_MOD(extack, "User setup the recover to fail for testing purposes"); + return -EINVAL; + } + if (ctx) { + health->recovered_break_msg = kstrdup(ctx->break_msg, + GFP_KERNEL); + if (!health->recovered_break_msg) + return -ENOMEM; + } + return 0; +} + +static int nsim_dev_dummy_fmsg_put(struct devlink_fmsg *fmsg, u32 binary_len) +{ + char *binary; + int err; + int i; + + err = devlink_fmsg_bool_pair_put(fmsg, "test_bool", true); + if (err) + return err; + err = devlink_fmsg_u8_pair_put(fmsg, "test_u8", 1); + if (err) + return err; + err = devlink_fmsg_u32_pair_put(fmsg, "test_u32", 3); + if (err) + return err; + err = devlink_fmsg_u64_pair_put(fmsg, "test_u64", 4); + if (err) + return err; + err = devlink_fmsg_string_pair_put(fmsg, "test_string", "somestring"); + if (err) + return err; + + binary = kmalloc(binary_len, GFP_KERNEL); + if (!binary) + return -ENOMEM; + get_random_bytes(binary, binary_len); + err = devlink_fmsg_binary_pair_put(fmsg, "test_binary", + binary, binary_len); + kfree(binary); + if (err) + return err; + + err = devlink_fmsg_pair_nest_start(fmsg, "test_nest"); + if (err) + return err; + err = devlink_fmsg_obj_nest_start(fmsg); + if (err) + return err; + err = devlink_fmsg_bool_pair_put(fmsg, "nested_test_bool", false); + if (err) + return err; + err = devlink_fmsg_u8_pair_put(fmsg, "nested_test_u8", false); + if (err) + return err; + err = devlink_fmsg_obj_nest_end(fmsg); + if (err) + return err; + err = devlink_fmsg_pair_nest_end(fmsg); + if (err) + return err; + + err = devlink_fmsg_arr_pair_nest_start(fmsg, "test_bool_array"); + if (err) + return err; + for (i = 0; i < 10; i++) { + err = devlink_fmsg_bool_put(fmsg, true); + if (err) + return err; + } + err = devlink_fmsg_arr_pair_nest_end(fmsg); + if (err) + return err; + + err = devlink_fmsg_arr_pair_nest_start(fmsg, "test_u8_array"); + if (err) + return err; + for (i = 0; i < 10; i++) { + err = devlink_fmsg_u8_put(fmsg, i); + if (err) + return err; + } + err = devlink_fmsg_arr_pair_nest_end(fmsg); + if (err) + return err; + + err = devlink_fmsg_arr_pair_nest_start(fmsg, "test_u32_array"); + if (err) + return err; + for (i = 0; i < 10; i++) { + err = devlink_fmsg_u32_put(fmsg, i); + if (err) + return err; + } + err = devlink_fmsg_arr_pair_nest_end(fmsg); + if (err) + return err; + + err = devlink_fmsg_arr_pair_nest_start(fmsg, "test_u64_array"); + if (err) + return err; + for (i = 0; i < 10; i++) { + err = devlink_fmsg_u64_put(fmsg, i); + if (err) + return err; + } + err = devlink_fmsg_arr_pair_nest_end(fmsg); + if (err) + return err; + + err = devlink_fmsg_arr_pair_nest_start(fmsg, "test_array_of_objects"); + if (err) + return err; + for (i = 0; i < 10; i++) { + err = devlink_fmsg_obj_nest_start(fmsg); + if (err) + return err; + err = devlink_fmsg_bool_pair_put(fmsg, + "in_array_nested_test_bool", + false); + if (err) + return err; + err = devlink_fmsg_u8_pair_put(fmsg, + "in_array_nested_test_u8", + i); + if (err) + return err; + err = devlink_fmsg_obj_nest_end(fmsg); + if (err) + return err; + } + return devlink_fmsg_arr_pair_nest_end(fmsg); +} + +static int +nsim_dev_dummy_reporter_dump(struct devlink_health_reporter *reporter, + struct devlink_fmsg *fmsg, void *priv_ctx, + struct netlink_ext_ack *extack) +{ + struct nsim_dev_health *health = devlink_health_reporter_priv(reporter); + struct nsim_dev_dummy_reporter_ctx *ctx = priv_ctx; + int err; + + if (ctx) { + err = devlink_fmsg_string_pair_put(fmsg, "break_message", + ctx->break_msg); + if (err) + return err; + } + return nsim_dev_dummy_fmsg_put(fmsg, health->binary_len); +} + +static int +nsim_dev_dummy_reporter_diagnose(struct devlink_health_reporter *reporter, + struct devlink_fmsg *fmsg, + struct netlink_ext_ack *extack) +{ + struct nsim_dev_health *health = devlink_health_reporter_priv(reporter); + int err; + + if (health->recovered_break_msg) { + err = devlink_fmsg_string_pair_put(fmsg, + "recovered_break_message", + health->recovered_break_msg); + if (err) + return err; + } + return nsim_dev_dummy_fmsg_put(fmsg, health->binary_len); +} + +static const +struct devlink_health_reporter_ops nsim_dev_dummy_reporter_ops = { + .name = "dummy", + .recover = nsim_dev_dummy_reporter_recover, + .dump = nsim_dev_dummy_reporter_dump, + .diagnose = nsim_dev_dummy_reporter_diagnose, +}; + +static ssize_t nsim_dev_health_break_write(struct file *file, + const char __user *data, + size_t count, loff_t *ppos) +{ + struct nsim_dev_health *health = file->private_data; + struct nsim_dev_dummy_reporter_ctx ctx; + char *break_msg; + int err; + + break_msg = kmalloc(count + 1, GFP_KERNEL); + if (!break_msg) + return -ENOMEM; + + if (copy_from_user(break_msg, data, count)) { + err = -EFAULT; + goto out; + } + break_msg[count] = '\0'; + if (break_msg[count - 1] == '\n') + break_msg[count - 1] = '\0'; + + ctx.break_msg = break_msg; + err = devlink_health_report(health->dummy_reporter, break_msg, &ctx); + if (err) + goto out; + +out: + kfree(break_msg); + return err ? err : count; +} + +static const struct file_operations nsim_dev_health_break_fops = { + .open = simple_open, + .write = nsim_dev_health_break_write, + .llseek = generic_file_llseek, +}; + +int nsim_dev_health_init(struct nsim_dev *nsim_dev, struct devlink *devlink) +{ + struct nsim_dev_health *health = &nsim_dev->health; + int err; + + health->empty_reporter = + devlink_health_reporter_create(devlink, + &nsim_dev_empty_reporter_ops, + 0, false, health); + if (IS_ERR(health->empty_reporter)) + return PTR_ERR(health->empty_reporter); + + health->dummy_reporter = + devlink_health_reporter_create(devlink, + &nsim_dev_dummy_reporter_ops, + 0, false, health); + if (IS_ERR(health->dummy_reporter)) { + err = PTR_ERR(health->dummy_reporter); + goto err_empty_reporter_destroy; + } + + health->ddir = debugfs_create_dir("health", nsim_dev->ddir); + if (IS_ERR_OR_NULL(health->ddir)) + return PTR_ERR_OR_ZERO(health->ddir) ?: -EINVAL; + + health->recovered_break_msg = NULL; + debugfs_create_file("break_health", 0200, health->ddir, health, + &nsim_dev_health_break_fops); + health->binary_len = 16; + debugfs_create_u32("binary_len", 0600, health->ddir, + &health->binary_len); + health->fail_recover = false; + debugfs_create_bool("fail_recover", 0600, health->ddir, + &health->fail_recover); + return 0; + +err_empty_reporter_destroy: + devlink_health_reporter_destroy(health->empty_reporter); + return err; +} + +void nsim_dev_health_exit(struct nsim_dev *nsim_dev) +{ + struct nsim_dev_health *health = &nsim_dev->health; + + debugfs_remove_recursive(health->ddir); + kfree(health->recovered_break_msg); + devlink_health_reporter_destroy(health->dummy_reporter); + devlink_health_reporter_destroy(health->empty_reporter); +} diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h index 24358385d869..657cbae50293 100644 --- a/drivers/net/netdevsim/netdevsim.h +++ b/drivers/net/netdevsim/netdevsim.h @@ -18,6 +18,7 @@ #include <linux/list.h> #include <linux/netdevice.h> #include <linux/u64_stats_sync.h> +#include <linux/debugfs.h> #include <net/devlink.h> #include <net/xdp.h> @@ -134,6 +135,18 @@ enum nsim_resource_id { NSIM_RESOURCE_IPV6_FIB_RULES, }; +struct nsim_dev_health { + struct devlink_health_reporter *empty_reporter; + struct devlink_health_reporter *dummy_reporter; + struct dentry *ddir; + char *recovered_break_msg; + u32 binary_len; + bool fail_recover; +}; + +int nsim_dev_health_init(struct nsim_dev *nsim_dev, struct devlink *devlink); +void nsim_dev_health_exit(struct nsim_dev *nsim_dev); + struct nsim_dev_port { struct list_head list; struct devlink_port devlink_port; @@ -164,6 +177,7 @@ struct nsim_dev { bool dont_allow_reload; bool fail_reload; struct devlink_region *dummy_region; + struct nsim_dev_health health; }; static inline struct net *nsim_dev_net(struct nsim_dev *nsim_dev)