@@ -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+
163175enum 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
694750void 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
733792fail_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
775837fail_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