From: Li Xiasong <lixiasong1@huawei.com> hulk inclusion category: feature bugzilla: https://atomgit.com/openeuler/kernel/issues/9198 -------------------------------- Tuple resolution for ntuple rules may require netdevice address lookup under rtnl protection. Doing this in the listen-side path causes locking context issues and may trigger invalid lock usage from RCU-related context. Move tuple resolution to cfg_work, and only queue a socket snapshot from the listen-side path. This keeps the locking in a sleepable worker context while preserving the existing async rule programming flow. Signed-off-by: Li Xiasong <lixiasong1@huawei.com> Signed-off-by: Yue Haibing <yuehaibing@huawei.com> --- net/venetcls/venetcls.h | 7 ++++++ net/venetcls/venetcls_ntuple.c | 46 ++++++++++++++++++++++------------ 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/net/venetcls/venetcls.h b/net/venetcls/venetcls.h index 4313939e91d9..83e2f9baa228 100644 --- a/net/venetcls/venetcls.h +++ b/net/venetcls/venetcls.h @@ -132,6 +132,13 @@ struct cfg_param { struct work_struct work; struct cmd_context ctx; struct sock *sk; + struct { + struct net *net; + u16 family; + u16 lport; + __be32 rcv_saddr_v4; + struct in6_addr rcv_saddr_v6; + } sk_snapshot; bool is_del; int nid; int cpu; diff --git a/net/venetcls/venetcls_ntuple.c b/net/venetcls/venetcls_ntuple.c index c770fa5e69de..6044465d0bba 100644 --- a/net/venetcls/venetcls_ntuple.c +++ b/net/venetcls/venetcls_ntuple.c @@ -211,33 +211,34 @@ static void get_first_ip6_addr(struct net *net, u32 *dip6) rtnl_unlock(); } -static void get_sk_rule_addr(struct sock *sk, struct cfg_param *ctx_p) +static void get_sk_rule_addr(struct cfg_param *ctx_p) { - bool is_ipv6 = !!(sk->sk_family == AF_INET6); + bool is_ipv6 = !!(ctx_p->sk_snapshot.family == AF_INET6); u16 *dport = &ctx_p->ctx.dport; u32 *dip4 = &ctx_p->ctx.dip4; u32 *dip6 = &ctx_p->ctx.dip6[0]; - *dport = htons(sk->sk_num); + *dport = htons(ctx_p->sk_snapshot.lport); ctx_p->ctx.is_ipv6 = is_ipv6; if (!match_ip_flag) { *dip4 = 0; - memset(dip6, 0, sizeof(sk->sk_v6_rcv_saddr)); + memset(dip6, 0, sizeof(ctx_p->sk_snapshot.rcv_saddr_v6)); return; } if (is_ipv6) { - if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr)) - memcpy(dip6, &sk->sk_v6_rcv_saddr, sizeof(sk->sk_v6_rcv_saddr)); + if (!ipv6_addr_any(&ctx_p->sk_snapshot.rcv_saddr_v6)) + memcpy(dip6, &ctx_p->sk_snapshot.rcv_saddr_v6, + sizeof(ctx_p->sk_snapshot.rcv_saddr_v6)); else - get_first_ip6_addr(sock_net(sk), dip6); + get_first_ip6_addr(ctx_p->sk_snapshot.net, dip6); } else { - if (sk->sk_rcv_saddr) - *dip4 = sk->sk_rcv_saddr; + if (ctx_p->sk_snapshot.rcv_saddr_v4) + *dip4 = ctx_p->sk_snapshot.rcv_saddr_v4; else - *dip4 = get_first_ip4_addr(sock_net(sk)); + *dip4 = get_first_ip4_addr(ctx_p->sk_snapshot.net); } } @@ -476,6 +477,8 @@ static void cfg_work(struct work_struct *work) struct vecls_sk_rule *rule; int devid, rxq_id, err; + get_sk_rule_addr(ctx_p); + mutex_lock(&vecls_sk_rules.mutex); for (devid = 0; devid < vecls_netdev_num; devid++) { vecls_dev = get_vecls_netdev_info(devid); @@ -527,6 +530,7 @@ static void cfg_work(struct work_struct *work) } } mutex_unlock(&vecls_sk_rules.mutex); + put_net(ctx_p->sk_snapshot.net); kfree(ctx_p); atomic_dec(&vecls_worker_count); } @@ -558,10 +562,15 @@ static void del_ntuple_rule(struct sock *sk) ctx_p = kzalloc(sizeof(*ctx_p), GFP_ATOMIC); if (!ctx_p) return; - get_sk_rule_addr(sk, ctx_p); ctx_p->is_del = true; ctx_p->sk = sk; + ctx_p->sk_snapshot.net = get_net(sock_net(sk)); + ctx_p->sk_snapshot.family = sk->sk_family; + ctx_p->sk_snapshot.lport = sk->sk_num; + ctx_p->sk_snapshot.rcv_saddr_v4 = sk->sk_rcv_saddr; + ctx_p->sk_snapshot.rcv_saddr_v6 = sk->sk_v6_rcv_saddr; + INIT_WORK(&ctx_p->work, cfg_work); queue_work(do_cfg_workqueue, &ctx_p->work); atomic_inc(&vecls_worker_count); @@ -570,8 +579,7 @@ static void del_ntuple_rule(struct sock *sk) static void add_ntuple_rule(struct sock *sk) { struct cfg_param *ctx_p; - int cpu = raw_smp_processor_id(); - int nid = cpu_to_node(cpu); + int cpu; if (check_appname(current->comm)) return; @@ -579,12 +587,18 @@ static void add_ntuple_rule(struct sock *sk) ctx_p = kzalloc(sizeof(*ctx_p), GFP_ATOMIC); if (!ctx_p) return; - get_sk_rule_addr(sk, ctx_p); + cpu = raw_smp_processor_id(); ctx_p->is_del = false; - ctx_p->sk = sk; - ctx_p->nid = nid; ctx_p->cpu = cpu; + ctx_p->nid = cpu_to_node(cpu); + ctx_p->sk = sk; + ctx_p->sk_snapshot.net = get_net(sock_net(sk)); + ctx_p->sk_snapshot.family = sk->sk_family; + ctx_p->sk_snapshot.lport = sk->sk_num; + ctx_p->sk_snapshot.rcv_saddr_v4 = sk->sk_rcv_saddr; + ctx_p->sk_snapshot.rcv_saddr_v6 = sk->sk_v6_rcv_saddr; + INIT_WORK(&ctx_p->work, cfg_work); queue_work(do_cfg_workqueue, &ctx_p->work); atomic_inc(&vecls_worker_count); -- 2.34.1