]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
tipc: Store struct sock in struct udp_bearer.
authorKuniyuki Iwashima <kuniyu@google.com>
Sat, 2 May 2026 03:13:07 +0000 (03:13 +0000)
committerJakub Kicinski <kuba@kernel.org>
Wed, 6 May 2026 00:47:06 +0000 (17:47 -0700)
tipc udp_bearer does not need to access struct socket itself in
the fast path; it only reads struct sock, and struct socket is
only used for tunnel setup and teardown.

Let's store struct sock directly in struct udp_bearer.

Note that cleanup_bearer() calls synchronize_net() after
udp_tunnel_sock_release(), so udp_bearer is not freed until
inflight fast paths finish.

Note also that synchronize_rcu() is added in the error path
of tipc_udp_enable() since udp_bearer will be kfree()d
immediately once we remove synchronize_rcu() in
udp_tunnel_sock_release().

This can be later converted to kfree_rcu().

Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20260502031401.3557229-15-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/tipc/udp_media.c

index 0db172f1a41aa7e3229e2338f102e586ae75b793..988b8a7f953ad6da860e6190f1f244650f121dce 100644 (file)
@@ -89,14 +89,14 @@ struct udp_replicast {
 /**
  * struct udp_bearer - ip/udp bearer data structure
  * @bearer:    associated generic tipc bearer
- * @ubsock:    bearer associated socket
+ * @sk:                bearer associated socket
  * @ifindex:   local address scope
  * @work:      used to schedule deferred work on a bearer
  * @rcast:     associated udp_replicast container
  */
 struct udp_bearer {
        struct tipc_bearer __rcu *bearer;
-       struct socket *ubsock;
+       struct sock *sk;
        u32 ifindex;
        struct work_struct work;
        struct udp_replicast rcast;
@@ -194,7 +194,7 @@ static int tipc_udp_xmit(struct net *net, struct sk_buff *skb,
                }
 
                ttl = ip4_dst_hoplimit(&rt->dst);
-               udp_tunnel_xmit_skb(rt, ub->ubsock->sk, skb, src->ipv4.s_addr,
+               udp_tunnel_xmit_skb(rt, ub->sk, skb, src->ipv4.s_addr,
                                    dst->ipv4.s_addr, 0, ttl, 0, src->port,
                                    dst->port, false, true, 0);
 #if IS_ENABLED(CONFIG_IPV6)
@@ -206,7 +206,7 @@ static int tipc_udp_xmit(struct net *net, struct sk_buff *skb,
                                .saddr = src->ipv6,
                                .flowi6_proto = IPPROTO_UDP
                        };
-                       ndst = ip6_dst_lookup_flow(net, ub->ubsock->sk,
+                       ndst = ip6_dst_lookup_flow(net, ub->sk,
                                                   &fl6, NULL);
                        if (IS_ERR(ndst)) {
                                err = PTR_ERR(ndst);
@@ -215,7 +215,7 @@ static int tipc_udp_xmit(struct net *net, struct sk_buff *skb,
                        dst_cache_set_ip6(cache, ndst, &fl6.saddr);
                }
                ttl = ip6_dst_hoplimit(ndst);
-               udp_tunnel6_xmit_skb(ndst, ub->ubsock->sk, skb, NULL,
+               udp_tunnel6_xmit_skb(ndst, ub->sk, skb, NULL,
                                     &src->ipv6, &dst->ipv6, 0, ttl, 0,
                                     src->port, dst->port, false, 0);
 #endif
@@ -405,9 +405,9 @@ out:
 
 static int enable_mcast(struct udp_bearer *ub, struct udp_media_addr *remote)
 {
-       int err = 0;
+       struct sock *sk = ub->sk;
        struct ip_mreqn mreqn;
-       struct sock *sk = ub->ubsock->sk;
+       int err = 0;
 
        if (ntohs(remote->proto) == ETH_P_IP) {
                mreqn.imr_multiaddr = remote->ipv4;
@@ -670,6 +670,7 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,
        struct nlattr *opts[TIPC_NLA_UDP_MAX + 1];
        u8 node_id[NODE_ID_LEN] = {0,};
        struct net_device *dev;
+       struct socket *sock;
        int rmcast = 0;
 
        ub = kzalloc_obj(*ub, GFP_ATOMIC);
@@ -764,14 +765,16 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,
                goto err;
        }
        udp_conf.local_udp_port = local.port;
-       err = udp_sock_create(net, &udp_conf, &ub->ubsock);
+       err = udp_sock_create(net, &udp_conf, &sock);
        if (err)
                goto err;
+
+       ub->sk = sock->sk;
        tuncfg.sk_user_data = ub;
        tuncfg.encap_type = 1;
        tuncfg.encap_rcv = tipc_udp_recv;
        tuncfg.encap_destroy = NULL;
-       setup_udp_tunnel_sock(net, ub->ubsock->sk, &tuncfg);
+       setup_udp_tunnel_sock(net, ub->sk, &tuncfg);
 
        err = dst_cache_init(&ub->rcast.dst_cache, GFP_ATOMIC);
        if (err)
@@ -793,7 +796,8 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,
 
 free:
        dst_cache_destroy(&ub->rcast.dst_cache);
-       udp_tunnel_sock_release(ub->ubsock->sk);
+       udp_tunnel_sock_release(ub->sk);
+       synchronize_rcu();
 err:
        kfree(ub);
        return err;
@@ -812,10 +816,10 @@ static void cleanup_bearer(struct work_struct *work)
                kfree_rcu(rcast, rcu);
        }
 
-       tn = tipc_net(sock_net(ub->ubsock->sk));
+       tn = tipc_net(sock_net(ub->sk));
 
        dst_cache_destroy(&ub->rcast.dst_cache);
-       udp_tunnel_sock_release(ub->ubsock->sk);
+       udp_tunnel_sock_release(ub->sk);
 
        /* Note: could use a call_rcu() to avoid another synchronize_net() */
        synchronize_net();
@@ -833,11 +837,11 @@ static void tipc_udp_disable(struct tipc_bearer *b)
                pr_err("UDP bearer instance not found\n");
                return;
        }
-       sock_set_flag(ub->ubsock->sk, SOCK_DEAD);
+       sock_set_flag(ub->sk, SOCK_DEAD);
        RCU_INIT_POINTER(ub->bearer, NULL);
 
        /* sock_release need to be done outside of rtnl lock */
-       atomic_inc(&tipc_net(sock_net(ub->ubsock->sk))->wq_count);
+       atomic_inc(&tipc_net(sock_net(ub->sk))->wq_count);
        INIT_WORK(&ub->work, cleanup_bearer);
        schedule_work(&ub->work);
 }