Skip to content

Commit c4837b9

Browse files
q2venPaolo Abeni
authored andcommitted
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 <[email protected]> Acked-by: Paolo Abeni <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
1 parent c9cabe0 commit c4837b9

File tree

1 file changed

+62
-33
lines changed

1 file changed

+62
-33
lines changed

net/ipv6/route.c

Lines changed: 62 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3729,15 +3729,13 @@ void fib6_nh_release_dsts(struct fib6_nh *fib6_nh)
37293729
}
37303730

37313731
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)
37343734
{
37353735
struct net *net = cfg->fc_nlinfo.nl_net;
3736-
struct fib6_info *rt = NULL;
37373736
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;
37413739

37423740
if (cfg->fc_nlinfo.nlh &&
37433741
!(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) {
@@ -3749,35 +3747,35 @@ static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg,
37493747
} else {
37503748
table = fib6_new_table(net, cfg->fc_table);
37513749
}
3750+
if (!table) {
3751+
err = -ENOBUFS;
3752+
goto err;
3753+
}
37523754

3753-
if (!table)
3754-
goto out;
3755-
3756-
err = -ENOMEM;
37573755
rt = fib6_info_alloc(gfp_flags, !cfg->fc_nh_id);
3758-
if (!rt)
3759-
goto out;
3756+
if (!rt) {
3757+
err = -ENOMEM;
3758+
goto err;
3759+
}
37603760

37613761
rt->fib6_metrics = ip_fib_metrics_init(cfg->fc_mx, cfg->fc_mx_len,
37623762
extack);
37633763
if (IS_ERR(rt->fib6_metrics)) {
37643764
err = PTR_ERR(rt->fib6_metrics);
3765-
/* Do not leave garbage there. */
3766-
rt->fib6_metrics = (struct dst_metrics *)&dst_default_metrics;
3767-
goto out_free;
3765+
goto free;
37683766
}
37693767

37703768
if (cfg->fc_flags & RTF_ADDRCONF)
37713769
rt->dst_nocount = true;
37723770

37733771
if (cfg->fc_flags & RTF_EXPIRES)
37743772
fib6_set_expires(rt, jiffies +
3775-
clock_t_to_jiffies(cfg->fc_expires));
3773+
clock_t_to_jiffies(cfg->fc_expires));
37763774

37773775
if (cfg->fc_protocol == RTPROT_UNSPEC)
37783776
cfg->fc_protocol = RTPROT_BOOT;
3779-
rt->fib6_protocol = cfg->fc_protocol;
37803777

3778+
rt->fib6_protocol = cfg->fc_protocol;
37813779
rt->fib6_table = table;
37823780
rt->fib6_metric = cfg->fc_metric;
37833781
rt->fib6_type = cfg->fc_type ? : RTN_UNICAST;
@@ -3790,6 +3788,20 @@ static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg,
37903788
ipv6_addr_prefix(&rt->fib6_src.addr, &cfg->fc_src, cfg->fc_src_len);
37913789
rt->fib6_src.plen = cfg->fc_src_len;
37923790
#endif
3791+
return rt;
3792+
free:
3793+
kfree(rt);
3794+
err:
3795+
return ERR_PTR(err);
3796+
}
3797+
3798+
static int ip6_route_info_create_nh(struct fib6_info *rt,
3799+
struct fib6_config *cfg,
3800+
struct netlink_ext_ack *extack)
3801+
{
3802+
struct net *net = cfg->fc_nlinfo.nl_net;
3803+
struct fib6_nh *fib6_nh;
3804+
int err;
37933805

37943806
if (cfg->fc_nh_id) {
37953807
struct nexthop *nh;
@@ -3814,9 +3826,11 @@ static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg,
38143826
rt->nh = nh;
38153827
fib6_nh = nexthop_fib6_nh(rt->nh);
38163828
} else {
3817-
err = fib6_nh_init(net, rt->fib6_nh, cfg, gfp_flags, extack);
3829+
int addr_type;
3830+
3831+
err = fib6_nh_init(net, rt->fib6_nh, cfg, GFP_ATOMIC, extack);
38183832
if (err)
3819-
goto out;
3833+
goto out_release;
38203834

38213835
fib6_nh = rt->fib6_nh;
38223836

@@ -3835,21 +3849,20 @@ static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg,
38353849
if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) {
38363850
NL_SET_ERR_MSG(extack, "Invalid source address");
38373851
err = -EINVAL;
3838-
goto out;
3852+
goto out_release;
38393853
}
38403854
rt->fib6_prefsrc.addr = cfg->fc_prefsrc;
38413855
rt->fib6_prefsrc.plen = 128;
3842-
} else
3843-
rt->fib6_prefsrc.plen = 0;
3856+
}
38443857

3845-
return rt;
3846-
out:
3858+
return 0;
3859+
out_release:
38473860
fib6_info_release(rt);
3848-
return ERR_PTR(err);
3861+
return err;
38493862
out_free:
38503863
ip_fib_metrics_put(rt->fib6_metrics);
38513864
kfree(rt);
3852-
return ERR_PTR(err);
3865+
return err;
38533866
}
38543867

38553868
int ip6_route_add(struct fib6_config *cfg, gfp_t gfp_flags,
@@ -3862,6 +3875,10 @@ int ip6_route_add(struct fib6_config *cfg, gfp_t gfp_flags,
38623875
if (IS_ERR(rt))
38633876
return PTR_ERR(rt);
38643877

3878+
err = ip6_route_info_create_nh(rt, cfg, extack);
3879+
if (err)
3880+
return err;
3881+
38653882
err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, extack);
38663883
fib6_info_release(rt);
38673884

@@ -4585,6 +4602,7 @@ struct fib6_info *addrconf_f6i_alloc(struct net *net,
45854602
.fc_ignore_dev_down = true,
45864603
};
45874604
struct fib6_info *f6i;
4605+
int err;
45884606

45894607
if (anycast) {
45904608
cfg.fc_type = RTN_ANYCAST;
@@ -4595,14 +4613,19 @@ struct fib6_info *addrconf_f6i_alloc(struct net *net,
45954613
}
45964614

45974615
f6i = ip6_route_info_create(&cfg, gfp_flags, extack);
4598-
if (!IS_ERR(f6i)) {
4599-
f6i->dst_nocount = true;
4616+
if (IS_ERR(f6i))
4617+
return f6i;
46004618

4601-
if (!anycast &&
4602-
(READ_ONCE(net->ipv6.devconf_all->disable_policy) ||
4603-
READ_ONCE(idev->cnf.disable_policy)))
4604-
f6i->dst_nopolicy = true;
4605-
}
4619+
err = ip6_route_info_create_nh(f6i, &cfg, extack);
4620+
if (err)
4621+
return ERR_PTR(err);
4622+
4623+
f6i->dst_nocount = true;
4624+
4625+
if (!anycast &&
4626+
(READ_ONCE(net->ipv6.devconf_all->disable_policy) ||
4627+
READ_ONCE(idev->cnf.disable_policy)))
4628+
f6i->dst_nopolicy = true;
46064629

46074630
return f6i;
46084631
}
@@ -5400,6 +5423,12 @@ static int ip6_route_multipath_add(struct fib6_config *cfg,
54005423
goto cleanup;
54015424
}
54025425

5426+
err = ip6_route_info_create_nh(rt, &r_cfg, extack);
5427+
if (err) {
5428+
rt = NULL;
5429+
goto cleanup;
5430+
}
5431+
54035432
rt->fib6_nh->fib_nh_weight = rtnh->rtnh_hops + 1;
54045433

54055434
err = ip6_route_info_append(info->nl_net, &rt6_nh_list,

0 commit comments

Comments
 (0)