[PATCH net-next 7/9] sit: dynamically allocate struct ip_tunnel_parm_kern
From: Eric Dumazet <edumazet@google.com>
Date: 2026-09-07 07:59:00
Subsystem:
networking [general], networking [ipv4/ipv6], the rest · Maintainers:
"David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, David Ahern, Ido Schimmel, Linus Torvalds
In preparation for converting SIT configuration parameters to RCU, dynamically allocate struct ip_tunnel_parm_kern as sit_parms in struct ip_tunnel. Signed-off-by: Eric Dumazet <edumazet@google.com> --- include/net/ip_tunnels.h | 1 + net/ipv6/sit.c | 152 +++++++++++++++++++++++---------------- 2 files changed, 92 insertions(+), 61 deletions(-)
diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h
index 7fff59bab53b682ac0d1efd1f47082ba7d633fd2..f464c4480edaf35f9ace1c5081c564ce51fed636 100644
--- a/include/net/ip_tunnels.h
+++ b/include/net/ip_tunnels.h@@ -190,6 +190,7 @@ struct ip_tunnel { #endif struct ip_tunnel_prl_entry __rcu *prl; /* potential router list */ unsigned int prl_count; /* # of entries in PRL */ + struct ip_tunnel_parm_kern *sit_parms; unsigned int ip_tnl_net_id; struct gro_cells gro_cells; __u32 fwmark;
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 35c6695909014a2c335f1de7afb48f07b7c91c39..dc37c7109af5324f2ced0301b289e7622dd1a55f 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c@@ -108,24 +108,24 @@ static struct ip_tunnel *ipip6_tunnel_lookup(struct net *net, int ifindex = dev ? dev->ifindex : 0; for_each_ip_tunnel_rcu(t, sitn->tunnels_r_l[h0 ^ h1]) { - if (local == t->parms.iph.saddr && - remote == t->parms.iph.daddr && - (!dev || !t->parms.link || ifindex == t->parms.link || - sifindex == t->parms.link) && + if (local == t->sit_parms->iph.saddr && + remote == t->sit_parms->iph.daddr && + (!dev || !t->sit_parms->link || ifindex == t->sit_parms->link || + sifindex == t->sit_parms->link) && (t->dev->flags & IFF_UP)) return t; } for_each_ip_tunnel_rcu(t, sitn->tunnels_r[h0]) { - if (remote == t->parms.iph.daddr && - (!dev || !t->parms.link || ifindex == t->parms.link || - sifindex == t->parms.link) && + if (remote == t->sit_parms->iph.daddr && + (!dev || !t->sit_parms->link || ifindex == t->sit_parms->link || + sifindex == t->sit_parms->link) && (t->dev->flags & IFF_UP)) return t; } for_each_ip_tunnel_rcu(t, sitn->tunnels_l[h1]) { - if (local == t->parms.iph.saddr && - (!dev || !t->parms.link || ifindex == t->parms.link || - sifindex == t->parms.link) && + if (local == t->sit_parms->iph.saddr && + (!dev || !t->sit_parms->link || ifindex == t->sit_parms->link || + sifindex == t->sit_parms->link) && (t->dev->flags & IFF_UP)) return t; }
@@ -157,7 +157,7 @@ __ipip6_bucket(struct sit_net *sitn, struct ip_tunnel_parm_kern *parms) static inline struct ip_tunnel __rcu **ipip6_bucket(struct sit_net *sitn, struct ip_tunnel *t) { - return __ipip6_bucket(sitn, &t->parms); + return __ipip6_bucket(sitn, t->sit_parms); } static void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t)
@@ -236,10 +236,11 @@ static int ipip6_tunnel_create(struct net_device *dev) if (err < 0) goto out; - __dev_addr_set(dev, &t->parms.iph.saddr, 4); - memcpy(dev->broadcast, &t->parms.iph.daddr, 4); + t->parms = *t->sit_parms; + __dev_addr_set(dev, &t->sit_parms->iph.saddr, 4); + memcpy(dev->broadcast, &t->sit_parms->iph.daddr, 4); - if (test_bit(IP_TUNNEL_SIT_ISATAP_BIT, t->parms.i_flags)) + if (test_bit(IP_TUNNEL_SIT_ISATAP_BIT, t->sit_parms->i_flags)) dev->priv_flags |= IFF_ISATAP; dev->rtnl_link_ops = &sit_link_ops;
@@ -270,9 +271,9 @@ static struct ip_tunnel *ipip6_tunnel_locate(struct net *net, for (tp = __ipip6_bucket(sitn, parms); (t = rtnl_dereference(*tp)) != NULL; tp = &t->next) { - if (local == t->parms.iph.saddr && - remote == t->parms.iph.daddr && - parms->link == t->parms.link) { + if (local == t->sit_parms->iph.saddr && + remote == t->sit_parms->iph.daddr && + parms->link == t->sit_parms->link) { if (create) return NULL; else
@@ -299,7 +300,10 @@ static struct ip_tunnel *ipip6_tunnel_locate(struct net *net, nt = netdev_priv(dev); nt->net = net; - nt->parms = *parms; + nt->sit_parms = kmalloc_obj(*nt->sit_parms); + if (!nt->sit_parms) + goto failed_free; + *nt->sit_parms = *parms; if (ipip6_tunnel_create(dev) < 0) goto failed_free;
@@ -602,12 +606,12 @@ static int ipip6_err(struct sk_buff *skb, u32 info) if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { ipv4_update_pmtu(skb, dev_net(skb->dev), info, - t->parms.link, iph->protocol); + t->sit_parms->link, iph->protocol); err = 0; goto out; } if (type == ICMP_REDIRECT) { - ipv4_redirect(skb, dev_net(skb->dev), t->parms.link, + ipv4_redirect(skb, dev_net(skb->dev), t->sit_parms->link, iph->protocol); err = 0; goto out;
@@ -618,10 +622,10 @@ static int ipip6_err(struct sk_buff *skb, u32 info) !ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4, type, data_len)) goto out; - if (t->parms.iph.daddr == 0) + if (t->sit_parms->iph.daddr == 0) goto out; - if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED) + if (t->sit_parms->iph.ttl == 0 && type == ICMP_TIME_EXCEEDED) goto out; if (time_before(jiffies, READ_ONCE(t->err_time) + IPTUNNEL_ERR_TIMEO))
@@ -722,8 +726,8 @@ static int ipip6_rcv(struct sk_buff *skb) tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev, iph->saddr, iph->daddr, sifindex); if (tunnel) { - if (tunnel->parms.iph.protocol != IPPROTO_IPV6 && - tunnel->parms.iph.protocol != 0) + if (tunnel->sit_parms->iph.protocol != IPPROTO_IPV6 && + tunnel->sit_parms->iph.protocol != 0) goto out; skb->mac_header = skb->network_header;
@@ -798,8 +802,8 @@ static int sit_tunnel_rcv(struct sk_buff *skb, u8 ipproto) if (tunnel) { const struct tnl_ptk_info *tpi; - if (tunnel->parms.iph.protocol != ipproto && - tunnel->parms.iph.protocol != 0) + if (tunnel->sit_parms->iph.protocol != ipproto && + tunnel->sit_parms->iph.protocol != 0) goto drop; if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
@@ -938,9 +942,9 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) { struct ip_tunnel *tunnel = netdev_priv(dev); - const struct iphdr *tiph = &tunnel->parms.iph; + const struct iphdr *tiph = &tunnel->sit_parms->iph; const struct ipv6hdr *iph6 = ipv6_hdr(skb); - u8 tos = tunnel->parms.iph.tos; + u8 tos = tunnel->sit_parms->iph.tos; __be16 df = tiph->frag_off; struct rtable *rt; /* Route to the other host */ struct net_device *tdev; /* Device to other host */
@@ -966,7 +970,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, if (!dst && !ipip6_tunnel_dst_find(skb, &dst, false)) goto tx_error; - flowi4_init_output(&fl4, tunnel->parms.link, READ_ONCE(tunnel->fwmark), + flowi4_init_output(&fl4, tunnel->sit_parms->link, READ_ONCE(tunnel->fwmark), tos & INET_DSCP_MASK, RT_SCOPE_UNIVERSE, IPPROTO_IPV6, 0, dst, tiph->saddr, 0, 0, sock_net_uid(tunnel->net, NULL));
@@ -1014,7 +1018,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, df = 0; } - if (tunnel->parms.iph.daddr) + if (tunnel->sit_parms->iph.daddr) skb_dst_update_pmtu_no_confirm(skb, mtu); if (skb->len > mtu && !skb_is_gso(skb)) {
@@ -1083,7 +1087,7 @@ static netdev_tx_t sit_tunnel_xmit__(struct sk_buff *skb, struct net_device *dev, u8 ipproto) { struct ip_tunnel *tunnel = netdev_priv(dev); - const struct iphdr *tiph = &tunnel->parms.iph; + const struct iphdr *tiph = &tunnel->sit_parms->iph; if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP4)) goto tx_error;
@@ -1138,7 +1142,7 @@ static void ipip6_tunnel_bind_dev(struct net_device *dev) const struct iphdr *iph; struct flowi4 fl4; - iph = &tunnel->parms.iph; + iph = &tunnel->sit_parms->iph; if (iph->daddr) { struct rtable *rt = ip_route_output_ports(tunnel->net, &fl4,
@@ -1147,7 +1151,7 @@ static void ipip6_tunnel_bind_dev(struct net_device *dev) 0, 0, IPPROTO_IPV6, iph->tos & INET_DSCP_MASK, - tunnel->parms.link); + tunnel->sit_parms->link); if (!IS_ERR(rt)) { tdev = rt->dst.dev;
@@ -1156,8 +1160,8 @@ static void ipip6_tunnel_bind_dev(struct net_device *dev) dev->flags |= IFF_POINTOPOINT; } - if (!tdev && tunnel->parms.link) - tdev = __dev_get_by_index(tunnel->net, tunnel->parms.link); + if (!tdev && tunnel->sit_parms->link) + tdev = __dev_get_by_index(tunnel->net, tunnel->sit_parms->link); if (tdev && !netif_is_l3_master(tdev)) { int mtu;
@@ -1171,30 +1175,41 @@ static void ipip6_tunnel_bind_dev(struct net_device *dev) dev->needed_headroom = ip_tunnel_limit_headroom(t_hlen + hlen); } -static void ipip6_tunnel_update(struct ip_tunnel *t, - struct ip_tunnel_parm_kern *p, - __u32 fwmark) +static int ipip6_tunnel_update(struct ip_tunnel *t, + struct ip_tunnel_parm_kern *p, + __u32 fwmark) { struct net *net = t->net; struct sit_net *sitn = net_generic(net, sit_net_id); + struct ip_tunnel_parm_kern *new_p, *old_p; + old_p = t->sit_parms; + new_p = kmalloc_obj(*new_p); + if (!new_p) + return -ENOMEM; + *new_p = *old_p; + new_p->iph.saddr = p->iph.saddr; + new_p->iph.daddr = p->iph.daddr; + new_p->iph.ttl = p->iph.ttl; + new_p->iph.tos = p->iph.tos; + new_p->iph.frag_off = p->iph.frag_off; + new_p->link = p->link; ipip6_tunnel_unlink(sitn, t); synchronize_net(); - t->parms.iph.saddr = p->iph.saddr; - t->parms.iph.daddr = p->iph.daddr; + t->sit_parms = new_p; + t->parms.iph = new_p->iph; + WRITE_ONCE(t->parms.link, new_p->link); __dev_addr_set(t->dev, &p->iph.saddr, 4); memcpy(t->dev->broadcast, &p->iph.daddr, 4); ipip6_tunnel_link(sitn, t); - t->parms.iph.ttl = p->iph.ttl; - t->parms.iph.tos = p->iph.tos; - t->parms.iph.frag_off = p->iph.frag_off; - if (t->parms.link != p->link || t->fwmark != fwmark) { - t->parms.link = p->link; + if (old_p->link != p->link || t->fwmark != fwmark) { WRITE_ONCE(t->fwmark, fwmark); ipip6_tunnel_bind_dev(t->dev); } dst_cache_reset(&t->dst_cache); netdev_state_change(t->dev); + kfree(old_p); + return 0; } #ifdef CONFIG_IPV6_SIT_6RD
@@ -1326,7 +1341,7 @@ ipip6_tunnel_get(struct net_device *dev, struct ip_tunnel_parm_kern *p) t = ipip6_tunnel_locate(t->net, p, 0); if (!t) t = netdev_priv(dev); - memcpy(p, &t->parms, sizeof(*p)); + memcpy(p, t->sit_parms, sizeof(*p)); return 0; }
@@ -1371,7 +1386,9 @@ ipip6_tunnel_change(struct net_device *dev, struct ip_tunnel_parm_kern *p) t = netdev_priv(dev); } - ipip6_tunnel_update(t, p, t->fwmark); + err = ipip6_tunnel_update(t, p, t->fwmark); + if (err) + return err; } return 0;
@@ -1448,7 +1465,7 @@ static int ipip6_get_iflink(const struct net_device *dev) { struct ip_tunnel *tunnel = netdev_priv(dev); - return READ_ONCE(tunnel->parms.link); + return READ_ONCE(tunnel->sit_parms->link); } static const struct net_device_ops ipip6_netdev_ops = {
@@ -1470,6 +1487,8 @@ static void ipip6_dev_free(struct net_device *dev) RCU_INIT_POINTER(tunnel->ip6rd, NULL); kfree(ip6rd); #endif + kfree(tunnel->sit_parms); + tunnel->sit_parms = NULL; if (tunnel->dst_cache.cache) { dst_cache_destroy(&tunnel->dst_cache); tunnel->dst_cache.cache = NULL;
@@ -1512,7 +1531,7 @@ static int ipip6_tunnel_init(struct net_device *dev) int err; tunnel->dev = dev; - strscpy(tunnel->parms.name, dev->name); + strscpy(tunnel->sit_parms->name, dev->name); ipip6_tunnel_bind_dev(dev);
@@ -1528,15 +1547,9 @@ static int ipip6_tunnel_init(struct net_device *dev) static void __net_init ipip6_fb_tunnel_init(struct net_device *dev) { struct ip_tunnel *tunnel = netdev_priv(dev); - struct iphdr *iph = &tunnel->parms.iph; struct net *net = dev_net(dev); struct sit_net *sitn = net_generic(net, sit_net_id); - iph->version = 4; - iph->protocol = IPPROTO_IPV6; - iph->ihl = 5; - iph->ttl = 64; - rcu_assign_pointer(sitn->tunnels_wc[0], tunnel); }
@@ -1623,6 +1636,7 @@ static int ipip6_newlink(struct net_device *dev, #ifdef CONFIG_IPV6_SIT_6RD struct ip_tunnel_6rd ip6rd; #endif + struct ip_tunnel_parm_kern p; struct net *net; int err;
@@ -1636,11 +1650,16 @@ static int ipip6_newlink(struct net_device *dev, return err; } - ipip6_netlink_parms(data, &nt->parms, &nt->fwmark); + ipip6_netlink_parms(data, &p, &nt->fwmark); - if (ipip6_tunnel_locate(net, &nt->parms, 0)) + if (ipip6_tunnel_locate(net, &p, 0)) return -EEXIST; + nt->sit_parms = kmalloc_obj(*nt->sit_parms); + if (!nt->sit_parms) + return -ENOMEM; + *nt->sit_parms = p; + err = ipip6_tunnel_create(dev); if (err < 0) { ipip6_dev_free(dev);
@@ -1707,7 +1726,9 @@ static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[], } else t = netdev_priv(dev); - ipip6_tunnel_update(t, &p, fwmark); + err = ipip6_tunnel_update(t, &p, fwmark); + if (err) + return err; #ifdef CONFIG_IPV6_SIT_6RD if (ipip6_netlink_6rd_parms(data, &ip6rd))
@@ -1762,7 +1783,7 @@ static size_t ipip6_get_size(const struct net_device *dev) static int ipip6_fill_info(struct sk_buff *skb, const struct net_device *dev) { struct ip_tunnel *tunnel = netdev_priv(dev); - struct ip_tunnel_parm_kern *parm = &tunnel->parms; + struct ip_tunnel_parm_kern *parm = tunnel->sit_parms; #ifdef CONFIG_IPV6_SIT_6RD const struct ip_tunnel_6rd_parm *ip6rd; #endif
@@ -1935,6 +1956,17 @@ static int __net_init sit_init_net(struct net *net) t = netdev_priv(sitn->fb_tunnel_dev); t->net = net; + t->sit_parms = kzalloc_obj(*t->sit_parms); + if (!t->sit_parms) { + err = -ENOMEM; + goto err_reg_dev; + } + t->sit_parms->iph.version = 4; + t->sit_parms->iph.protocol = IPPROTO_IPV6; + t->sit_parms->iph.ihl = 5; + t->sit_parms->iph.ttl = 64; + strscpy(t->sit_parms->name, sitn->fb_tunnel_dev->name); + t->parms = *t->sit_parms; err = ipip6_tunnel_clone_6rd(sitn->fb_tunnel_dev, sitn); if (err < 0)
@@ -1945,8 +1977,6 @@ static int __net_init sit_init_net(struct net *net) goto err_reg_dev; ipip6_fb_tunnel_init(sitn->fb_tunnel_dev); - - strscpy(t->parms.name, sitn->fb_tunnel_dev->name); return 0; err_reg_dev:
--
2.55.0.979.g7e5102b832-goog