hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/ICBFCS -------------------------------- Use workqueue for ntuple cfg to avoid mutex_lock in rcu context. Fixes: d60758b0ffcd ("net/oenetcls: introduce oenetcls for network optimization") Signed-off-by: Wang Liang <wangliang74@huawei.com> --- net/oenetcls/oenetcls.h | 14 ++- net/oenetcls/oenetcls_flow.c | 24 ++++- net/oenetcls/oenetcls_main.c | 26 ++++-- net/oenetcls/oenetcls_ntuple.c | 166 +++++++++++++++++++++------------ 4 files changed, 152 insertions(+), 78 deletions(-) diff --git a/net/oenetcls/oenetcls.h b/net/oenetcls/oenetcls.h index b2c4a3c61956..f2726582db91 100644 --- a/net/oenetcls/oenetcls.h +++ b/net/oenetcls/oenetcls.h @@ -74,7 +74,7 @@ struct oecls_sk_rule { int dport; int action; int ruleid; - int nid; + int cpu; }; struct oecls_sk_entry { @@ -121,6 +121,14 @@ struct rmgr_ctrl { __u32 size; }; +struct cfg_param { + struct work_struct work; + struct cmd_context ctx; + struct sock *sk; + bool is_del; + int cpu; +}; + extern int match_ip_flag; extern int debug; extern int oecls_netdev_num; @@ -169,9 +177,9 @@ int check_appname(char *task_name); int send_ethtool_ioctl(struct cmd_context *ctx, void *cmd); int alloc_rxq_id(int nid, int devid); void free_rxq_id(int nid, int devid, int rxq_id); -void oecls_ntuple_res_init(void); +int oecls_ntuple_res_init(void); void oecls_ntuple_res_clean(void); -void oecls_flow_res_init(void); +int oecls_flow_res_init(void); void oecls_flow_res_clean(void); #define L0_MAX_PAGE_SIZE (8192) diff --git a/net/oenetcls/oenetcls_flow.c b/net/oenetcls/oenetcls_flow.c index 37daee93b205..3834f500f75d 100644 --- a/net/oenetcls/oenetcls_flow.c +++ b/net/oenetcls/oenetcls_flow.c @@ -40,7 +40,7 @@ static bool _oecls_timeout(struct net_device *dev, u16 rxq_index, if (flow_table && flow_id <= flow_table->mask) { rflow = &flow_table->flows[flow_id]; cpu = READ_ONCE(rflow->cpu); - oecls_debug("dev:%s, rxq:%d, flow_id:%u, filter_id:%d/%d, cpu:%d", dev->name, + oecls_debug("dev:%s, rxq:%d, flow_id:%u, filter_id:%d/%d, cpu:%d\n", dev->name, rxq_index, flow_id, filter_id, rflow->filter, cpu); if (rflow->filter == filter_id && cpu < nr_cpu_ids) { @@ -390,16 +390,30 @@ static const struct oecls_hook_ops oecls_flow_ops = { .oecls_cfg_rxcls = NULL, }; -void oecls_flow_res_init(void) +int oecls_flow_res_init(void) { - oecls_sock_flow_table_init(); - oecls_dev_flow_table_init(); + int err; + + err = oecls_sock_flow_table_init(); + if (err) + return err; + + err = oecls_dev_flow_table_init(); + if (err) { + oecls_sock_flow_table_release(); + return err; + } + RCU_INIT_POINTER(oecls_ops, &oecls_flow_ops); + synchronize_rcu(); + return 0; } void oecls_flow_res_clean(void) { - RCU_INIT_POINTER(oecls_ops, NULL); + rcu_assign_pointer(oecls_ops, NULL); + synchronize_rcu(); + oecls_sock_flow_table_release(); oecls_dev_flow_table_release(); } diff --git a/net/oenetcls/oenetcls_main.c b/net/oenetcls/oenetcls_main.c index 88ddaec1a363..e5920351aada 100644 --- a/net/oenetcls/oenetcls_main.c +++ b/net/oenetcls/oenetcls_main.c @@ -39,6 +39,10 @@ static int strategy; module_param(strategy, int, 0444); MODULE_PARM_DESC(strategy, "strategy, default 0"); +static int check_cap = 1; +module_param(check_cap, int, 0444); +MODULE_PARM_DESC(check_cap, "check_cap, default 1"); + static bool check_params(void) { if (mode != 0 && mode != 1) @@ -288,7 +292,7 @@ static int dev_ethtool_kern(struct net *net, struct ifreq *ifr) case ETHTOOL_GCHANNELS: break; default: - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) + if (check_cap && !ns_capable(net->user_ns, CAP_NET_ADMIN)) return -EPERM; } @@ -669,9 +673,8 @@ static int init_numa_rxq_bitmap(int nid, struct oecls_numa_info *numa_info) return ret; } -static int get_cluster_rxq(struct oecls_numa_bound_dev_info *bound_dev) +static int get_cluster_rxq(int cpu, struct oecls_numa_bound_dev_info *bound_dev) { - int cpu = raw_smp_processor_id(); int cluster_id = cpu / oecls_cluster_cpu_num; int i, j, rxq_id; @@ -710,10 +713,11 @@ static int put_cluster_rxq(struct oecls_numa_bound_dev_info *bound_dev, int rxq_ return -1; } -int alloc_rxq_id(int nid, int devid) +int alloc_rxq_id(int cpu, int devid) { struct oecls_numa_bound_dev_info *bound_dev; struct oecls_numa_info *numa_info; + int nid = cpu_to_node(cpu); int rxq_id; numa_info = get_oecls_numa_info(nid); @@ -729,7 +733,7 @@ int alloc_rxq_id(int nid, int devid) bound_dev = &numa_info->bound_dev[devid]; if (strategy == 1) { - rxq_id = get_cluster_rxq(bound_dev); + rxq_id = get_cluster_rxq(cpu, bound_dev); if (rxq_id < 0 || rxq_id >= OECLS_MAX_RXQ_NUM_PER_DEV) pr_info("failed to get rxq_id:%d in cluster, try numa\n", rxq_id); else @@ -744,14 +748,15 @@ int alloc_rxq_id(int nid, int devid) found: clear_bit(rxq_id, bound_dev->bitmap_rxq); - oecls_debug("alloc nid:%d, dev_id:%d, rxq_id:%d\n", nid, devid, rxq_id); + oecls_debug("alloc cpu:%d, nid:%d, devid:%d, rxq_id:%d\n", cpu, nid, devid, rxq_id); return rxq_id; } -void free_rxq_id(int nid, int devid, int rxq_id) +void free_rxq_id(int cpu, int devid, int rxq_id) { struct oecls_numa_bound_dev_info *bound_dev; struct oecls_numa_info *numa_info; + int nid = cpu_to_node(cpu); numa_info = get_oecls_numa_info(nid); if (!numa_info) { @@ -1039,9 +1044,12 @@ static __init int oecls_init(void) #endif if (mode == 0) - oecls_ntuple_res_init(); + err = oecls_ntuple_res_init(); else - oecls_flow_res_init(); + err = oecls_flow_res_init(); + + if (err) + goto clean_rxq; return 0; diff --git a/net/oenetcls/oenetcls_ntuple.c b/net/oenetcls/oenetcls_ntuple.c index 53b877294dc5..5bb1b1916a4c 100644 --- a/net/oenetcls/oenetcls_ntuple.c +++ b/net/oenetcls/oenetcls_ntuple.c @@ -11,6 +11,8 @@ #include "oenetcls.h" struct oecls_sk_rule_list oecls_sk_rules, oecls_sk_list; +static struct workqueue_struct *do_cfg_workqueue; +static atomic_t oecls_worker_count = ATOMIC_INIT(0); static void init_oecls_sk_rules(void) { @@ -31,8 +33,7 @@ static inline struct hlist_head *get_sk_hashlist(void *sk) return oecls_sk_list.hash + (jhash(sk, sizeof(sk), 0) & OECLS_SK_RULE_HASHMASK); } -static void add_sk_rule(int devid, u32 dip4, u16 dport, void *sk, int action, - int ruleid, int nid) +static void add_sk_rule(int devid, u32 dip4, u16 dport, void *sk, int action, int ruleid, int cpu) { struct hlist_head *hlist = get_rule_hashlist(dip4, dport); struct hlist_head *sk_hlist = get_sk_hashlist(sk); @@ -50,7 +51,7 @@ static void add_sk_rule(int devid, u32 dip4, u16 dport, void *sk, int action, rule->devid = devid; rule->action = action; rule->ruleid = ruleid; - rule->nid = nid; + rule->cpu = cpu; hlist_add_head(&rule->node, hlist); entry->sk = sk; @@ -421,85 +422,113 @@ static int cfg_ethtool_rule(struct cmd_context *ctx, bool is_del) return ret; } -static void del_ntuple_rule(struct sock *sk) +static void cfg_work(struct work_struct *work) { + struct cfg_param *ctx_p = container_of(work, struct cfg_param, work); struct oecls_netdev_info *oecls_dev; - struct cmd_context ctx = { 0 }; struct oecls_sk_rule *rule; - int devid; - u16 dport; - u32 dip4; + int devid, rxq_id; int err; - get_sk_rule_addr(sk, &dip4, &dport); - mutex_lock(&oecls_sk_rules.mutex); for_each_oecls_netdev(devid, oecls_dev) { - strncpy(ctx.netdev, oecls_dev->dev_name, IFNAMSIZ); - rule = get_rule_from_sk(devid, sk); - if (!rule) { - oecls_debug("rule not found! sk:%p, devid:%d, dip4:%pI4, dport:%d\n", - sk, devid, &dip4, ntohs(dport)); - continue; - } + strncpy(ctx_p->ctx.netdev, oecls_dev->dev_name, IFNAMSIZ); + if (!ctx_p->is_del) { + if (reuseport_check(devid, ctx_p->ctx.dip4, ctx_p->ctx.dport)) { + oecls_error("dip4:%pI4, dport:%d reuse!\n", &ctx_p->ctx.dip4, + ctx_p->ctx.dport); + continue; + } - // Config Ntuple rule to dev - ctx.del_ruleid = rule->ruleid; - err = cfg_ethtool_rule(&ctx, true); - if (err) { - oecls_error("del sk:%p, nid:%d, devid:%d, action:%d, ruleid:%d, err:%d\n", - sk, rule->nid, devid, rule->action, rule->ruleid, err); - } + // Calculate the bound queue + rxq_id = alloc_rxq_id(ctx_p->cpu, devid); + if (rxq_id < 0) + continue; - // Free the bound queue - free_rxq_id(rule->nid, devid, rule->action); + // Config Ntuple rule to dev + ctx_p->ctx.action = (u16)rxq_id; + err = cfg_ethtool_rule(&ctx_p->ctx, ctx_p->is_del); + // Add sk rule only on success + if (err) { + free_rxq_id(ctx_p->cpu, devid, rxq_id); + continue; + } + add_sk_rule(devid, ctx_p->ctx.dip4, ctx_p->ctx.dport, ctx_p->sk, + ctx_p->ctx.action, ctx_p->ctx.ret_loc, ctx_p->cpu); + } else { + rule = get_rule_from_sk(devid, ctx_p->sk); + if (!rule) { + oecls_debug("rule not found! sk:%p, devid:%d, dip4:%pI4, dport:%d\n", + ctx_p->sk, devid, &ctx_p->ctx.dip4, + ntohs(ctx_p->ctx.dport)); + continue; + } - // Delete sk rule - del_sk_rule(rule); + // Config Ntuple rule to dev + ctx_p->ctx.del_ruleid = rule->ruleid; + err = cfg_ethtool_rule(&ctx_p->ctx, ctx_p->is_del); + // Free the bound queue + free_rxq_id(rule->cpu, devid, rule->action); + // Delete sk rule + del_sk_rule(rule); + } } mutex_unlock(&oecls_sk_rules.mutex); + kfree(ctx_p); + atomic_dec(&oecls_worker_count); } -static void add_ntuple_rule(struct sock *sk) +static bool has_sock_rule(struct sock *sk) { struct oecls_netdev_info *oecls_dev; - struct cmd_context ctx = { 0 }; - int cpu = raw_smp_processor_id(); - int nid = cpu_to_node(cpu); - int rxq_id; + struct oecls_sk_rule *rule; int devid; - int err; - if (check_appname(current->comm)) + for_each_oecls_netdev(devid, oecls_dev) { + rule = get_rule_from_sk(devid, sk); + if (rule) + return true; + } + return false; +} + +static void del_ntuple_rule(struct sock *sk) +{ + struct cfg_param *ctx_p; + + if (!has_sock_rule(sk)) return; - get_sk_rule_addr(sk, &ctx.dip4, &ctx.dport); - mutex_lock(&oecls_sk_rules.mutex); - for_each_oecls_netdev(devid, oecls_dev) { - strncpy(ctx.netdev, oecls_dev->dev_name, IFNAMSIZ); - if (reuseport_check(devid, ctx.dip4, ctx.dport)) { - oecls_error("dip4:0x%x, dport:%d reuse!\n", ctx.dip4, ctx.dport); - continue; - } + ctx_p = kzalloc(sizeof(*ctx_p), GFP_ATOMIC); + if (!ctx_p) + return; + get_sk_rule_addr(sk, &ctx_p->ctx.dip4, &ctx_p->ctx.dport); - // Calculate the bound queue - rxq_id = alloc_rxq_id(nid, devid); - if (rxq_id < 0) - continue; + ctx_p->is_del = true; + ctx_p->sk = sk; + INIT_WORK(&ctx_p->work, cfg_work); + queue_work(do_cfg_workqueue, &ctx_p->work); + atomic_inc(&oecls_worker_count); +} - // Config Ntuple rule to dev - ctx.action = (u16)rxq_id; - err = cfg_ethtool_rule(&ctx, false); - if (err) { - oecls_error("add sk:%p, nid:%d, devid:%d, action:%d, ruleid:%d, err:%d\n", - sk, nid, devid, ctx.action, ctx.ret_loc, err); - continue; - } +static void add_ntuple_rule(struct sock *sk) +{ + struct cfg_param *ctx_p; - // Add sk rule - add_sk_rule(devid, ctx.dip4, ctx.dport, sk, ctx.action, ctx.ret_loc, nid); - } - mutex_unlock(&oecls_sk_rules.mutex); + if (check_appname(current->comm)) + return; + + ctx_p = kzalloc(sizeof(*ctx_p), GFP_ATOMIC); + if (!ctx_p) + return; + get_sk_rule_addr(sk, &ctx_p->ctx.dip4, &ctx_p->ctx.dport); + + ctx_p->is_del = false; + ctx_p->sk = sk; + ctx_p->cpu = raw_smp_processor_id(); + INIT_WORK(&ctx_p->work, cfg_work); + queue_work(do_cfg_workqueue, &ctx_p->work); + atomic_inc(&oecls_worker_count); } static void ethtool_cfg_rxcls(struct sock *sk, int is_del) @@ -558,14 +587,29 @@ static const struct oecls_hook_ops oecls_ntuple_ops = { .oecls_cfg_rxcls = ethtool_cfg_rxcls, }; -void oecls_ntuple_res_init(void) +int oecls_ntuple_res_init(void) { + do_cfg_workqueue = alloc_ordered_workqueue("oecls_cfg", 0); + if (!do_cfg_workqueue) { + oecls_debug("alloc_ordered_workqueue fails\n"); + return -ENOMEM; + } + init_oecls_sk_rules(); RCU_INIT_POINTER(oecls_ops, &oecls_ntuple_ops); + synchronize_rcu(); + return 0; } void oecls_ntuple_res_clean(void) { - RCU_INIT_POINTER(oecls_ops, NULL); + rcu_assign_pointer(oecls_ops, NULL); + synchronize_rcu(); + + oecls_debug("oecls_worker_count:%d\n", atomic_read(&oecls_worker_count)); + while (atomic_read(&oecls_worker_count) != 0) + mdelay(1); + + destroy_workqueue(do_cfg_workqueue); clean_oecls_sk_rules(); } -- 2.34.1