Skip to content

Commit 0ad722b

Browse files
zhouhui-Coriginedavem330
authored andcommitted
nfp: flower: fix for take a mutex lock in soft irq context and rcu lock
The neighbour event callback call the function nfp_tun_write_neigh, this function will take a mutex lock and it is in soft irq context, change the work queue to process the neighbour event. Move the nfp_tun_write_neigh function out of range rcu_read_lock/unlock() in function nfp_tunnel_request_route_v4 and nfp_tunnel_request_route_v6. Fixes: abc2109 ("nfp: flower: tunnel neigh support bond offload") CC: [email protected] # 6.2+ Signed-off-by: Hui Zhou <[email protected]> Signed-off-by: Louis Peens <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 803a809 commit 0ad722b

File tree

1 file changed

+95
-32
lines changed

1 file changed

+95
-32
lines changed

drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c

Lines changed: 95 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,18 @@ struct nfp_tun_mac_addr_offload {
160160
u8 addr[ETH_ALEN];
161161
};
162162

163+
/**
164+
* struct nfp_neigh_update_work - update neighbour information to nfp
165+
* @work: Work queue for writing neigh to the nfp
166+
* @n: neighbour entry
167+
* @app: Back pointer to app
168+
*/
169+
struct nfp_neigh_update_work {
170+
struct work_struct work;
171+
struct neighbour *n;
172+
struct nfp_app *app;
173+
};
174+
163175
enum nfp_flower_mac_offload_cmd {
164176
NFP_TUNNEL_MAC_OFFLOAD_ADD = 0,
165177
NFP_TUNNEL_MAC_OFFLOAD_DEL = 1,
@@ -607,38 +619,30 @@ nfp_tun_write_neigh(struct net_device *netdev, struct nfp_app *app,
607619
nfp_flower_cmsg_warn(app, "Neighbour configuration failed.\n");
608620
}
609621

610-
static int
611-
nfp_tun_neigh_event_handler(struct notifier_block *nb, unsigned long event,
612-
void *ptr)
622+
static void
623+
nfp_tun_release_neigh_update_work(struct nfp_neigh_update_work *update_work)
613624
{
614-
struct nfp_flower_priv *app_priv;
615-
struct netevent_redirect *redir;
616-
struct neighbour *n;
625+
neigh_release(update_work->n);
626+
kfree(update_work);
627+
}
628+
629+
static void nfp_tun_neigh_update(struct work_struct *work)
630+
{
631+
struct nfp_neigh_update_work *update_work;
617632
struct nfp_app *app;
633+
struct neighbour *n;
618634
bool neigh_invalid;
619635
int err;
620636

621-
switch (event) {
622-
case NETEVENT_REDIRECT:
623-
redir = (struct netevent_redirect *)ptr;
624-
n = redir->neigh;
625-
break;
626-
case NETEVENT_NEIGH_UPDATE:
627-
n = (struct neighbour *)ptr;
628-
break;
629-
default:
630-
return NOTIFY_DONE;
631-
}
632-
633-
neigh_invalid = !(n->nud_state & NUD_VALID) || n->dead;
634-
635-
app_priv = container_of(nb, struct nfp_flower_priv, tun.neigh_nb);
636-
app = app_priv->app;
637+
update_work = container_of(work, struct nfp_neigh_update_work, work);
638+
app = update_work->app;
639+
n = update_work->n;
637640

638641
if (!nfp_flower_get_port_id_from_netdev(app, n->dev))
639-
return NOTIFY_DONE;
642+
goto out;
640643

641644
#if IS_ENABLED(CONFIG_INET)
645+
neigh_invalid = !(n->nud_state & NUD_VALID) || n->dead;
642646
if (n->tbl->family == AF_INET6) {
643647
#if IS_ENABLED(CONFIG_IPV6)
644648
struct flowi6 flow6 = {};
@@ -655,13 +659,11 @@ nfp_tun_neigh_event_handler(struct notifier_block *nb, unsigned long event,
655659
dst = ip6_dst_lookup_flow(dev_net(n->dev), NULL,
656660
&flow6, NULL);
657661
if (IS_ERR(dst))
658-
return NOTIFY_DONE;
662+
goto out;
659663

660664
dst_release(dst);
661665
}
662666
nfp_tun_write_neigh(n->dev, app, &flow6, n, true, false);
663-
#else
664-
return NOTIFY_DONE;
665667
#endif /* CONFIG_IPV6 */
666668
} else {
667669
struct flowi4 flow4 = {};
@@ -678,17 +680,71 @@ nfp_tun_neigh_event_handler(struct notifier_block *nb, unsigned long event,
678680
rt = ip_route_output_key(dev_net(n->dev), &flow4);
679681
err = PTR_ERR_OR_ZERO(rt);
680682
if (err)
681-
return NOTIFY_DONE;
683+
goto out;
682684

683685
ip_rt_put(rt);
684686
}
685687
nfp_tun_write_neigh(n->dev, app, &flow4, n, false, false);
686688
}
687-
#else
688-
return NOTIFY_DONE;
689689
#endif /* CONFIG_INET */
690+
out:
691+
nfp_tun_release_neigh_update_work(update_work);
692+
}
690693

691-
return NOTIFY_OK;
694+
static struct nfp_neigh_update_work *
695+
nfp_tun_alloc_neigh_update_work(struct nfp_app *app, struct neighbour *n)
696+
{
697+
struct nfp_neigh_update_work *update_work;
698+
699+
update_work = kzalloc(sizeof(*update_work), GFP_ATOMIC);
700+
if (!update_work)
701+
return NULL;
702+
703+
INIT_WORK(&update_work->work, nfp_tun_neigh_update);
704+
neigh_hold(n);
705+
update_work->n = n;
706+
update_work->app = app;
707+
708+
return update_work;
709+
}
710+
711+
static int
712+
nfp_tun_neigh_event_handler(struct notifier_block *nb, unsigned long event,
713+
void *ptr)
714+
{
715+
struct nfp_neigh_update_work *update_work;
716+
struct nfp_flower_priv *app_priv;
717+
struct netevent_redirect *redir;
718+
struct neighbour *n;
719+
struct nfp_app *app;
720+
721+
switch (event) {
722+
case NETEVENT_REDIRECT:
723+
redir = (struct netevent_redirect *)ptr;
724+
n = redir->neigh;
725+
break;
726+
case NETEVENT_NEIGH_UPDATE:
727+
n = (struct neighbour *)ptr;
728+
break;
729+
default:
730+
return NOTIFY_DONE;
731+
}
732+
#if IS_ENABLED(CONFIG_IPV6)
733+
if (n->tbl != ipv6_stub->nd_tbl && n->tbl != &arp_tbl)
734+
#else
735+
if (n->tbl != &arp_tbl)
736+
#endif
737+
return NOTIFY_DONE;
738+
739+
app_priv = container_of(nb, struct nfp_flower_priv, tun.neigh_nb);
740+
app = app_priv->app;
741+
update_work = nfp_tun_alloc_neigh_update_work(app, n);
742+
if (!update_work)
743+
return NOTIFY_DONE;
744+
745+
queue_work(system_highpri_wq, &update_work->work);
746+
747+
return NOTIFY_DONE;
692748
}
693749

694750
void nfp_tunnel_request_route_v4(struct nfp_app *app, struct sk_buff *skb)
@@ -706,6 +762,7 @@ void nfp_tunnel_request_route_v4(struct nfp_app *app, struct sk_buff *skb)
706762
netdev = nfp_app_dev_get(app, be32_to_cpu(payload->ingress_port), NULL);
707763
if (!netdev)
708764
goto fail_rcu_unlock;
765+
dev_hold(netdev);
709766

710767
flow.daddr = payload->ipv4_addr;
711768
flow.flowi4_proto = IPPROTO_UDP;
@@ -725,13 +782,16 @@ void nfp_tunnel_request_route_v4(struct nfp_app *app, struct sk_buff *skb)
725782
ip_rt_put(rt);
726783
if (!n)
727784
goto fail_rcu_unlock;
785+
rcu_read_unlock();
786+
728787
nfp_tun_write_neigh(n->dev, app, &flow, n, false, true);
729788
neigh_release(n);
730-
rcu_read_unlock();
789+
dev_put(netdev);
731790
return;
732791

733792
fail_rcu_unlock:
734793
rcu_read_unlock();
794+
dev_put(netdev);
735795
nfp_flower_cmsg_warn(app, "Requested route not found.\n");
736796
}
737797

@@ -749,6 +809,7 @@ void nfp_tunnel_request_route_v6(struct nfp_app *app, struct sk_buff *skb)
749809
netdev = nfp_app_dev_get(app, be32_to_cpu(payload->ingress_port), NULL);
750810
if (!netdev)
751811
goto fail_rcu_unlock;
812+
dev_hold(netdev);
752813

753814
flow.daddr = payload->ipv6_addr;
754815
flow.flowi6_proto = IPPROTO_UDP;
@@ -766,14 +827,16 @@ void nfp_tunnel_request_route_v6(struct nfp_app *app, struct sk_buff *skb)
766827
dst_release(dst);
767828
if (!n)
768829
goto fail_rcu_unlock;
830+
rcu_read_unlock();
769831

770832
nfp_tun_write_neigh(n->dev, app, &flow, n, true, true);
771833
neigh_release(n);
772-
rcu_read_unlock();
834+
dev_put(netdev);
773835
return;
774836

775837
fail_rcu_unlock:
776838
rcu_read_unlock();
839+
dev_put(netdev);
777840
nfp_flower_cmsg_warn(app, "Requested IPv6 route not found.\n");
778841
}
779842

0 commit comments

Comments
 (0)