Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ipv6: Split ip6_route_info_create().

We will get rid of RTNL from RTM_NEWROUTE and SIOCADDRT and rely
on RCU to guarantee dev and nexthop lifetime.

Then, we want to allocate as much as possible before entering
the RCU section.

The RCU section will start in the middle of ip6_route_info_create(),
and this is problematic for ip6_route_multipath_add() that calls
ip6_route_info_create() multiple times.

Let's split ip6_route_info_create() into two parts; one for memory
allocation and another for nexthop setup.

Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Acked-by: Paolo Abeni <pabeni@redhat.com>
Link: https://patch.msgid.link/20250418000443.43734-7-kuniyu@amazon.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Kuniyuki Iwashima and committed by
Paolo Abeni
c4837b98 c9cabe05

+62 -33
+62 -33
net/ipv6/route.c
··· 3729 3729 } 3730 3730 3731 3731 static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg, 3732 - gfp_t gfp_flags, 3733 - struct netlink_ext_ack *extack) 3732 + gfp_t gfp_flags, 3733 + struct netlink_ext_ack *extack) 3734 3734 { 3735 3735 struct net *net = cfg->fc_nlinfo.nl_net; 3736 - struct fib6_info *rt = NULL; 3737 3736 struct fib6_table *table; 3738 - struct fib6_nh *fib6_nh; 3739 - int err = -ENOBUFS; 3740 - int addr_type; 3737 + struct fib6_info *rt; 3738 + int err; 3741 3739 3742 3740 if (cfg->fc_nlinfo.nlh && 3743 3741 !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) { ··· 3747 3749 } else { 3748 3750 table = fib6_new_table(net, cfg->fc_table); 3749 3751 } 3752 + if (!table) { 3753 + err = -ENOBUFS; 3754 + goto err; 3755 + } 3750 3756 3751 - if (!table) 3752 - goto out; 3753 - 3754 - err = -ENOMEM; 3755 3757 rt = fib6_info_alloc(gfp_flags, !cfg->fc_nh_id); 3756 - if (!rt) 3757 - goto out; 3758 + if (!rt) { 3759 + err = -ENOMEM; 3760 + goto err; 3761 + } 3758 3762 3759 3763 rt->fib6_metrics = ip_fib_metrics_init(cfg->fc_mx, cfg->fc_mx_len, 3760 3764 extack); 3761 3765 if (IS_ERR(rt->fib6_metrics)) { 3762 3766 err = PTR_ERR(rt->fib6_metrics); 3763 - /* Do not leave garbage there. */ 3764 - rt->fib6_metrics = (struct dst_metrics *)&dst_default_metrics; 3765 - goto out_free; 3767 + goto free; 3766 3768 } 3767 3769 3768 3770 if (cfg->fc_flags & RTF_ADDRCONF) ··· 3770 3772 3771 3773 if (cfg->fc_flags & RTF_EXPIRES) 3772 3774 fib6_set_expires(rt, jiffies + 3773 - clock_t_to_jiffies(cfg->fc_expires)); 3775 + clock_t_to_jiffies(cfg->fc_expires)); 3774 3776 3775 3777 if (cfg->fc_protocol == RTPROT_UNSPEC) 3776 3778 cfg->fc_protocol = RTPROT_BOOT; 3777 - rt->fib6_protocol = cfg->fc_protocol; 3778 3779 3780 + rt->fib6_protocol = cfg->fc_protocol; 3779 3781 rt->fib6_table = table; 3780 3782 rt->fib6_metric = cfg->fc_metric; 3781 3783 rt->fib6_type = cfg->fc_type ? : RTN_UNICAST; ··· 3788 3790 ipv6_addr_prefix(&rt->fib6_src.addr, &cfg->fc_src, cfg->fc_src_len); 3789 3791 rt->fib6_src.plen = cfg->fc_src_len; 3790 3792 #endif 3793 + return rt; 3794 + free: 3795 + kfree(rt); 3796 + err: 3797 + return ERR_PTR(err); 3798 + } 3799 + 3800 + static int ip6_route_info_create_nh(struct fib6_info *rt, 3801 + struct fib6_config *cfg, 3802 + struct netlink_ext_ack *extack) 3803 + { 3804 + struct net *net = cfg->fc_nlinfo.nl_net; 3805 + struct fib6_nh *fib6_nh; 3806 + int err; 3791 3807 3792 3808 if (cfg->fc_nh_id) { 3793 3809 struct nexthop *nh; ··· 3826 3814 rt->nh = nh; 3827 3815 fib6_nh = nexthop_fib6_nh(rt->nh); 3828 3816 } else { 3829 - err = fib6_nh_init(net, rt->fib6_nh, cfg, gfp_flags, extack); 3817 + int addr_type; 3818 + 3819 + err = fib6_nh_init(net, rt->fib6_nh, cfg, GFP_ATOMIC, extack); 3830 3820 if (err) 3831 - goto out; 3821 + goto out_release; 3832 3822 3833 3823 fib6_nh = rt->fib6_nh; 3834 3824 ··· 3849 3835 if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) { 3850 3836 NL_SET_ERR_MSG(extack, "Invalid source address"); 3851 3837 err = -EINVAL; 3852 - goto out; 3838 + goto out_release; 3853 3839 } 3854 3840 rt->fib6_prefsrc.addr = cfg->fc_prefsrc; 3855 3841 rt->fib6_prefsrc.plen = 128; 3856 - } else 3857 - rt->fib6_prefsrc.plen = 0; 3842 + } 3858 3843 3859 - return rt; 3860 - out: 3844 + return 0; 3845 + out_release: 3861 3846 fib6_info_release(rt); 3862 - return ERR_PTR(err); 3847 + return err; 3863 3848 out_free: 3864 3849 ip_fib_metrics_put(rt->fib6_metrics); 3865 3850 kfree(rt); 3866 - return ERR_PTR(err); 3851 + return err; 3867 3852 } 3868 3853 3869 3854 int ip6_route_add(struct fib6_config *cfg, gfp_t gfp_flags, ··· 3874 3861 rt = ip6_route_info_create(cfg, gfp_flags, extack); 3875 3862 if (IS_ERR(rt)) 3876 3863 return PTR_ERR(rt); 3864 + 3865 + err = ip6_route_info_create_nh(rt, cfg, extack); 3866 + if (err) 3867 + return err; 3877 3868 3878 3869 err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, extack); 3879 3870 fib6_info_release(rt); ··· 4602 4585 .fc_ignore_dev_down = true, 4603 4586 }; 4604 4587 struct fib6_info *f6i; 4588 + int err; 4605 4589 4606 4590 if (anycast) { 4607 4591 cfg.fc_type = RTN_ANYCAST; ··· 4613 4595 } 4614 4596 4615 4597 f6i = ip6_route_info_create(&cfg, gfp_flags, extack); 4616 - if (!IS_ERR(f6i)) { 4617 - f6i->dst_nocount = true; 4598 + if (IS_ERR(f6i)) 4599 + return f6i; 4618 4600 4619 - if (!anycast && 4620 - (READ_ONCE(net->ipv6.devconf_all->disable_policy) || 4621 - READ_ONCE(idev->cnf.disable_policy))) 4622 - f6i->dst_nopolicy = true; 4623 - } 4601 + err = ip6_route_info_create_nh(f6i, &cfg, extack); 4602 + if (err) 4603 + return ERR_PTR(err); 4604 + 4605 + f6i->dst_nocount = true; 4606 + 4607 + if (!anycast && 4608 + (READ_ONCE(net->ipv6.devconf_all->disable_policy) || 4609 + READ_ONCE(idev->cnf.disable_policy))) 4610 + f6i->dst_nopolicy = true; 4624 4611 4625 4612 return f6i; 4626 4613 } ··· 5419 5396 rt = ip6_route_info_create(&r_cfg, GFP_KERNEL, extack); 5420 5397 if (IS_ERR(rt)) { 5421 5398 err = PTR_ERR(rt); 5399 + rt = NULL; 5400 + goto cleanup; 5401 + } 5402 + 5403 + err = ip6_route_info_create_nh(rt, &r_cfg, extack); 5404 + if (err) { 5422 5405 rt = NULL; 5423 5406 goto cleanup; 5424 5407 }