udp_tunnel{6,}_xmit_skb assume that a reference was taken on the dst passed to them, and use that reference. This forces callers to reference the dst, preventing noref optimizations. Convert udp_tunnel{6,}_xmit_skb to be noref and drop the requirement that a ref be taken on the dst. Signed-off-by: Marek Mietus --- drivers/net/amt.c | 3 +++ drivers/net/bareudp.c | 2 ++ drivers/net/geneve.c | 2 ++ drivers/net/gtp.c | 7 +++++++ drivers/net/ovpn/udp.c | 2 ++ drivers/net/vxlan/vxlan_core.c | 2 ++ drivers/net/wireguard/socket.c | 2 ++ net/ipv4/udp_tunnel_core.c | 3 --- net/ipv6/ip6_udp_tunnel.c | 2 +- net/sctp/ipv6.c | 3 +++ net/sctp/protocol.c | 4 ++++ net/tipc/udp_media.c | 2 ++ 12 files changed, 30 insertions(+), 4 deletions(-) diff --git a/drivers/net/amt.c b/drivers/net/amt.c index 902c817a0dea..e9eeaa7b6fe7 100644 --- a/drivers/net/amt.c +++ b/drivers/net/amt.c @@ -1050,6 +1050,7 @@ static bool amt_send_membership_update(struct amt_dev *amt, false, false, 0); + ip_rt_put(rt); amt_update_gw_status(amt, AMT_STATUS_SENT_UPDATE, true); return false; } @@ -1108,6 +1109,7 @@ static void amt_send_multicast_data(struct amt_dev *amt, false, false, 0); + ip_rt_put(rt); } static bool amt_send_membership_query(struct amt_dev *amt, @@ -1167,6 +1169,7 @@ static bool amt_send_membership_query(struct amt_dev *amt, false, false, 0); + ip_rt_put(rt); amt_update_relay_status(tunnel, AMT_STATUS_SENT_QUERY, true); return false; } diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c index 0df3208783ad..92ee4a36f86f 100644 --- a/drivers/net/bareudp.c +++ b/drivers/net/bareudp.c @@ -364,6 +364,7 @@ static int bareudp_xmit_skb(struct sk_buff *skb, struct net_device *dev, !net_eq(bareudp->net, dev_net(bareudp->dev)), !test_bit(IP_TUNNEL_CSUM_BIT, info->key.tun_flags), 0); + ip_rt_put(rt); return 0; free_dst: @@ -433,6 +434,7 @@ static int bareudp6_xmit_skb(struct sk_buff *skb, struct net_device *dev, !test_bit(IP_TUNNEL_CSUM_BIT, info->key.tun_flags), 0); + dst_release(dst); return 0; free_dst: diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 0949d4579171..cfc8e7b5f8f2 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -1396,6 +1396,7 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev, !net_eq(geneve->net, dev_net(geneve->dev)), !test_bit(IP_TUNNEL_CSUM_BIT, info->key.tun_flags), 0); + ip_rt_put(rt); return 0; } @@ -1487,6 +1488,7 @@ static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev, !test_bit(IP_TUNNEL_CSUM_BIT, info->key.tun_flags), 0); + dst_release(dst); return 0; } #endif diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index 4213c3b2d532..88dd36bb24b0 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -449,6 +449,7 @@ static int gtp0_send_echo_resp_ip(struct gtp_dev *gtp, struct sk_buff *skb) dev_net(gtp->dev)), false, 0); + ip_rt_put(rt); return 0; } @@ -708,6 +709,7 @@ static int gtp1u_send_echo_resp(struct gtp_dev *gtp, struct sk_buff *skb) dev_net(gtp->dev)), false, 0); + ip_rt_put(rt); return 0; } @@ -1308,6 +1310,7 @@ static netdev_tx_t gtp_dev_xmit(struct sk_buff *skb, struct net_device *dev) !net_eq(sock_net(pktinfo.pctx->sk), dev_net(dev)), false, 0); + ip_rt_put(pktinfo.rt); break; case AF_INET6: #if IS_ENABLED(CONFIG_IPV6) @@ -1318,6 +1321,7 @@ static netdev_tx_t gtp_dev_xmit(struct sk_buff *skb, struct net_device *dev) 0, pktinfo.gtph_port, pktinfo.gtph_port, false, 0); + dst_release(&pktinfo.rt6->dst); #else goto tx_err; #endif @@ -2400,6 +2404,7 @@ static int gtp_genl_send_echo_req(struct sk_buff *skb, struct genl_info *info) return -ENODEV; } + rcu_read_lock(); udp_tunnel_xmit_skb(rt, sk, skb_to_send, fl4.saddr, fl4.daddr, inet_dscp_to_dsfield(fl4.flowi4_dscp), @@ -2409,6 +2414,8 @@ static int gtp_genl_send_echo_req(struct sk_buff *skb, struct genl_info *info) !net_eq(sock_net(sk), dev_net(gtp->dev)), false, 0); + rcu_read_unlock(); + ip_rt_put(rt); return 0; } diff --git a/drivers/net/ovpn/udp.c b/drivers/net/ovpn/udp.c index d6a0f7a0b75d..c82ba71b6aff 100644 --- a/drivers/net/ovpn/udp.c +++ b/drivers/net/ovpn/udp.c @@ -200,6 +200,7 @@ static int ovpn_udp4_output(struct ovpn_peer *peer, struct ovpn_bind *bind, udp_tunnel_xmit_skb(rt, sk, skb, fl.saddr, fl.daddr, 0, ip4_dst_hoplimit(&rt->dst), 0, fl.fl4_sport, fl.fl4_dport, false, sk->sk_no_check_tx, 0); + ip_rt_put(rt); ret = 0; err: local_bh_enable(); @@ -275,6 +276,7 @@ static int ovpn_udp6_output(struct ovpn_peer *peer, struct ovpn_bind *bind, udp_tunnel6_xmit_skb(dst, sk, skb, skb->dev, &fl.saddr, &fl.daddr, 0, ip6_dst_hoplimit(dst), 0, fl.fl6_sport, fl.fl6_dport, udp_get_no_check6_tx(sk), 0); + dst_release(dst); ret = 0; err: local_bh_enable(); diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index 7bd0ae0a6a33..aacef14cd300 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -2540,6 +2540,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, pkey->u.ipv4.dst, tos, ttl, df, src_port, dst_port, xnet, !udp_sum, ipcb_flags); + ip_rt_put(rt); #if IS_ENABLED(CONFIG_IPV6) } else { struct vxlan_sock *sock6; @@ -2615,6 +2616,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, &saddr, &pkey->u.ipv6.dst, tos, ttl, pkey->label, src_port, dst_port, !udp_sum, ip6cb_flags); + dst_release(ndst); #endif } vxlan_vnifilter_count(vxlan, vni, NULL, VXLAN_VNI_STATS_TX, pkt_len); diff --git a/drivers/net/wireguard/socket.c b/drivers/net/wireguard/socket.c index 253488f8c00f..ee7d9c675909 100644 --- a/drivers/net/wireguard/socket.c +++ b/drivers/net/wireguard/socket.c @@ -85,6 +85,7 @@ static int send4(struct wg_device *wg, struct sk_buff *skb, udp_tunnel_xmit_skb(rt, sock, skb, fl.saddr, fl.daddr, ds, ip4_dst_hoplimit(&rt->dst), 0, fl.fl4_sport, fl.fl4_dport, false, false, 0); + ip_rt_put(rt); goto out; err: @@ -152,6 +153,7 @@ static int send6(struct wg_device *wg, struct sk_buff *skb, udp_tunnel6_xmit_skb(dst, sock, skb, skb->dev, &fl.saddr, &fl.daddr, ds, ip6_dst_hoplimit(dst), 0, fl.fl6_sport, fl.fl6_dport, false, 0); + dst_release(dst); goto out; err: diff --git a/net/ipv4/udp_tunnel_core.c b/net/ipv4/udp_tunnel_core.c index 8a91f36cc052..b1f667c52cb2 100644 --- a/net/ipv4/udp_tunnel_core.c +++ b/net/ipv4/udp_tunnel_core.c @@ -190,11 +190,8 @@ void udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb udp_set_csum(nocheck, skb, src, dst, skb->len); - rcu_read_lock(); iptunnel_xmit(sk, rt, skb, src, dst, IPPROTO_UDP, tos, ttl, df, xnet, ipcb_flags); - rcu_read_unlock(); - ip_rt_put(rt); } EXPORT_SYMBOL_GPL(udp_tunnel_xmit_skb); diff --git a/net/ipv6/ip6_udp_tunnel.c b/net/ipv6/ip6_udp_tunnel.c index cef3e0210744..d58815db8182 100644 --- a/net/ipv6/ip6_udp_tunnel.c +++ b/net/ipv6/ip6_udp_tunnel.c @@ -95,7 +95,7 @@ void udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk, uh->len = htons(skb->len); - skb_dst_set(skb, dst); + skb_dst_set_noref(skb, dst); udp6_set_csum(nocheck, skb, saddr, daddr, skb->len); diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 531cb0690007..54f489c4c41f 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -261,9 +261,12 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *t) skb_set_inner_ipproto(skb, IPPROTO_SCTP); label = ip6_make_flowlabel(sock_net(sk), skb, fl6->flowlabel, true, fl6); + rcu_read_lock(); udp_tunnel6_xmit_skb(dst, sk, skb, NULL, &fl6->saddr, &fl6->daddr, tclass, ip6_dst_hoplimit(dst), label, sctp_sk(sk)->udp_port, t->encap_port, false, 0); + rcu_read_unlock(); + dst_release(dst); return 0; } diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 2c3398f75d76..98e5dc217959 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -1070,10 +1070,14 @@ static inline int sctp_v4_xmit(struct sk_buff *skb, struct sctp_transport *t) skb_reset_inner_mac_header(skb); skb_reset_inner_transport_header(skb); skb_set_inner_ipproto(skb, IPPROTO_SCTP); + + rcu_read_lock(); udp_tunnel_xmit_skb(dst_rtable(dst), sk, skb, fl4->saddr, fl4->daddr, dscp, ip4_dst_hoplimit(dst), df, sctp_sk(sk)->udp_port, t->encap_port, false, false, 0); + rcu_read_unlock(); + dst_release(dst); return 0; } diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c index b85ab0fb3b8c..ba4ff5b3354f 100644 --- a/net/tipc/udp_media.c +++ b/net/tipc/udp_media.c @@ -198,6 +198,7 @@ static int tipc_udp_xmit(struct net *net, struct sk_buff *skb, udp_tunnel_xmit_skb(rt, ub->ubsock->sk, skb, src->ipv4.s_addr, dst->ipv4.s_addr, 0, ttl, 0, src->port, dst->port, false, true, 0); + ip_rt_put(rt); #if IS_ENABLED(CONFIG_IPV6) } else { if (!ndst) { @@ -220,6 +221,7 @@ static int tipc_udp_xmit(struct net *net, struct sk_buff *skb, udp_tunnel6_xmit_skb(ndst, ub->ubsock->sk, skb, NULL, &src->ipv6, &dst->ipv6, 0, ttl, 0, src->port, dst->port, false, 0); + dst_release(ndst); #endif } local_bh_enable(); -- 2.51.0