From 134c7532424067b3006024c1acc44bd195245622 Mon Sep 17 00:00:00 2001 From: Amit Cohen Date: Sun, 7 Feb 2021 10:22:56 +0200 Subject: [PATCH] netdevsim: fib: Add debugfs to debug route offload failure Add "fail_route_offload" flag to disallow offloading routes. It is needed to test "offload failed" notifications. Create the flag as part of nsim_fib_create() under fib directory and set it to false by default. When FIB_EVENT_ENTRY_{REPLACE, APPEND} are triggered and "fail_route_offload" value is true, set the appropriate hardware flag to make the kernel emit RTM_NEWROUTE notification with RTM_F_OFFLOAD_FAILED flag. Signed-off-by: Amit Cohen Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/netdevsim/fib.c | 114 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 112 insertions(+), 2 deletions(-) diff --git a/drivers/net/netdevsim/fib.c b/drivers/net/netdevsim/fib.c index b93bd48..46fb414 100644 --- a/drivers/net/netdevsim/fib.c +++ b/drivers/net/netdevsim/fib.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "netdevsim.h" @@ -53,6 +54,8 @@ struct nsim_fib_data { struct work_struct fib_event_work; struct list_head fib_event_queue; spinlock_t fib_event_queue_lock; /* Protects fib event queue list */ + struct dentry *ddir; + bool fail_route_offload; }; struct nsim_fib_rt_key { @@ -303,6 +306,25 @@ nsim_fib4_rt_lookup(struct rhashtable *fib_rt_ht, return container_of(fib_rt, struct nsim_fib4_rt, common); } +static void +nsim_fib4_rt_offload_failed_flag_set(struct net *net, + struct fib_entry_notifier_info *fen_info) +{ + u32 *p_dst = (u32 *)&fen_info->dst; + struct fib_rt_info fri; + + fri.fi = fen_info->fi; + fri.tb_id = fen_info->tb_id; + fri.dst = cpu_to_be32(*p_dst); + fri.dst_len = fen_info->dst_len; + fri.tos = fen_info->tos; + fri.type = fen_info->type; + fri.offload = false; + fri.trap = false; + fri.offload_failed = true; + fib_alias_hw_flags_set(net, &fri); +} + static void nsim_fib4_rt_hw_flags_set(struct net *net, const struct nsim_fib4_rt *fib4_rt, bool trap) @@ -384,6 +406,15 @@ static int nsim_fib4_rt_insert(struct nsim_fib_data *data, struct nsim_fib4_rt *fib4_rt, *fib4_rt_old; int err; + if (data->fail_route_offload) { + /* For testing purposes, user set debugfs fail_route_offload + * value to true. Simulate hardware programming latency and then + * fail. + */ + msleep(1); + return -EINVAL; + } + fib4_rt = nsim_fib4_rt_create(data, fen_info); if (!fib4_rt) return -ENOMEM; @@ -423,6 +454,11 @@ static int nsim_fib4_event(struct nsim_fib_data *data, switch (event) { case FIB_EVENT_ENTRY_REPLACE: err = nsim_fib4_rt_insert(data, fen_info); + if (err) { + struct net *net = devlink_net(data->devlink); + + nsim_fib4_rt_offload_failed_flag_set(net, fen_info); + } break; case FIB_EVENT_ENTRY_DEL: nsim_fib4_rt_remove(data, fen_info); @@ -564,6 +600,15 @@ static int nsim_fib6_rt_append(struct nsim_fib_data *data, struct nsim_fib6_rt *fib6_rt; int i, err; + if (data->fail_route_offload) { + /* For testing purposes, user set debugfs fail_route_offload + * value to true. Simulate hardware programming latency and then + * fail. + */ + msleep(1); + return -EINVAL; + } + fib6_rt = nsim_fib6_rt_lookup(&data->fib_rt_ht, rt); if (!fib6_rt) return -EINVAL; @@ -587,6 +632,26 @@ err_fib6_rt_nh_del: } #if IS_ENABLED(CONFIG_IPV6) +static void nsim_fib6_rt_offload_failed_flag_set(struct nsim_fib_data *data, + struct fib6_info **rt_arr, + unsigned int nrt6) + +{ + struct net *net = devlink_net(data->devlink); + int i; + + for (i = 0; i < nrt6; i++) + fib6_info_hw_flags_set(net, rt_arr[i], false, false, true); +} +#else +static void nsim_fib6_rt_offload_failed_flag_set(struct nsim_fib_data *data, + struct fib6_info **rt_arr, + unsigned int nrt6) +{ +} +#endif + +#if IS_ENABLED(CONFIG_IPV6) static void nsim_fib6_rt_hw_flags_set(struct nsim_fib_data *data, const struct nsim_fib6_rt *fib6_rt, bool trap) @@ -667,6 +732,15 @@ static int nsim_fib6_rt_insert(struct nsim_fib_data *data, struct nsim_fib6_rt *fib6_rt, *fib6_rt_old; int err; + if (data->fail_route_offload) { + /* For testing purposes, user set debugfs fail_route_offload + * value to true. Simulate hardware programming latency and then + * fail. + */ + msleep(1); + return -EINVAL; + } + fib6_rt = nsim_fib6_rt_create(data, fib6_event->rt_arr, fib6_event->nrt6); if (IS_ERR(fib6_rt)) @@ -764,7 +838,7 @@ static int nsim_fib6_event(struct nsim_fib_data *data, struct nsim_fib6_event *fib6_event, unsigned long event) { - int err = 0; + int err; if (fib6_event->rt_arr[0]->fib6_src.plen) return 0; @@ -772,9 +846,13 @@ static int nsim_fib6_event(struct nsim_fib_data *data, switch (event) { case FIB_EVENT_ENTRY_REPLACE: err = nsim_fib6_rt_insert(data, fib6_event); + if (err) + goto err_rt_offload_failed_flag_set; break; case FIB_EVENT_ENTRY_APPEND: err = nsim_fib6_rt_append(data, fib6_event); + if (err) + goto err_rt_offload_failed_flag_set; break; case FIB_EVENT_ENTRY_DEL: nsim_fib6_rt_remove(data, fib6_event); @@ -783,6 +861,11 @@ static int nsim_fib6_event(struct nsim_fib_data *data, break; } + return 0; + +err_rt_offload_failed_flag_set: + nsim_fib6_rt_offload_failed_flag_set(data, fib6_event->rt_arr, + fib6_event->nrt6); return err; } @@ -1290,10 +1373,29 @@ static void nsim_fib_event_work(struct work_struct *work) mutex_unlock(&data->fib_lock); } +static int +nsim_fib_debugfs_init(struct nsim_fib_data *data, struct nsim_dev *nsim_dev) +{ + data->ddir = debugfs_create_dir("fib", nsim_dev->ddir); + if (IS_ERR(data->ddir)) + return PTR_ERR(data->ddir); + + data->fail_route_offload = false; + debugfs_create_bool("fail_route_offload", 0600, data->ddir, + &data->fail_route_offload); + return 0; +} + +static void nsim_fib_debugfs_exit(struct nsim_fib_data *data) +{ + debugfs_remove_recursive(data->ddir); +} + struct nsim_fib_data *nsim_fib_create(struct devlink *devlink, struct netlink_ext_ack *extack) { struct nsim_fib_data *data; + struct nsim_dev *nsim_dev; int err; data = kzalloc(sizeof(*data), GFP_KERNEL); @@ -1301,10 +1403,15 @@ struct nsim_fib_data *nsim_fib_create(struct devlink *devlink, return ERR_PTR(-ENOMEM); data->devlink = devlink; - err = rhashtable_init(&data->nexthop_ht, &nsim_nexthop_ht_params); + nsim_dev = devlink_priv(devlink); + err = nsim_fib_debugfs_init(data, nsim_dev); if (err) goto err_data_free; + err = rhashtable_init(&data->nexthop_ht, &nsim_nexthop_ht_params); + if (err) + goto err_debugfs_exit; + mutex_init(&data->fib_lock); INIT_LIST_HEAD(&data->fib_rt_list); err = rhashtable_init(&data->fib_rt_ht, &nsim_fib_rt_ht_params); @@ -1365,6 +1472,8 @@ err_rhashtable_nexthop_destroy: rhashtable_free_and_destroy(&data->nexthop_ht, nsim_nexthop_free, data); mutex_destroy(&data->fib_lock); +err_debugfs_exit: + nsim_fib_debugfs_exit(data); err_data_free: kfree(data); return ERR_PTR(err); @@ -1392,5 +1501,6 @@ void nsim_fib_destroy(struct devlink *devlink, struct nsim_fib_data *data) WARN_ON_ONCE(!list_empty(&data->fib_event_queue)); WARN_ON_ONCE(!list_empty(&data->fib_rt_list)); mutex_destroy(&data->fib_lock); + nsim_fib_debugfs_exit(data); kfree(data); } -- 2.7.4