Skip to content

Commit 6edb3c9

Browse files
dsaherndavem330
authored andcommitted
net/ipv6: Defer initialization of dst to data path
Defer setting dst input, output and error until fib entry is copied. The reject path from ip6_route_info_create is moved to a new function ip6_rt_init_dst_reject with a helper doing the conversion from fib6_type to dst error. The remainder of the new ip6_rt_init_dst is an amalgamtion of dst code from addrconf_dst_alloc and the non-reject path of ip6_route_info_create. The dst output function is always ip6_output and the input function is either ip6_input (local routes), ip6_mc_input (multicast routes) or ip6_forward (anything else). A couple of places using dst.error are updated to look at rt6i_flags. Signed-off-by: David Ahern <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 5e670d8 commit 6edb3c9

File tree

1 file changed

+74
-41
lines changed

1 file changed

+74
-41
lines changed

net/ipv6/route.c

Lines changed: 74 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -920,6 +920,75 @@ static struct net_device *ip6_rt_get_dev_rcu(struct rt6_info *rt)
920920
return dev;
921921
}
922922

923+
static const int fib6_prop[RTN_MAX + 1] = {
924+
[RTN_UNSPEC] = 0,
925+
[RTN_UNICAST] = 0,
926+
[RTN_LOCAL] = 0,
927+
[RTN_BROADCAST] = 0,
928+
[RTN_ANYCAST] = 0,
929+
[RTN_MULTICAST] = 0,
930+
[RTN_BLACKHOLE] = -EINVAL,
931+
[RTN_UNREACHABLE] = -EHOSTUNREACH,
932+
[RTN_PROHIBIT] = -EACCES,
933+
[RTN_THROW] = -EAGAIN,
934+
[RTN_NAT] = -EINVAL,
935+
[RTN_XRESOLVE] = -EINVAL,
936+
};
937+
938+
static int ip6_rt_type_to_error(u8 fib6_type)
939+
{
940+
return fib6_prop[fib6_type];
941+
}
942+
943+
static void ip6_rt_init_dst_reject(struct rt6_info *rt, struct rt6_info *ort)
944+
{
945+
rt->dst.error = ip6_rt_type_to_error(ort->fib6_type);
946+
947+
switch (ort->fib6_type) {
948+
case RTN_BLACKHOLE:
949+
rt->dst.output = dst_discard_out;
950+
rt->dst.input = dst_discard;
951+
break;
952+
case RTN_PROHIBIT:
953+
rt->dst.output = ip6_pkt_prohibit_out;
954+
rt->dst.input = ip6_pkt_prohibit;
955+
break;
956+
case RTN_THROW:
957+
case RTN_UNREACHABLE:
958+
default:
959+
rt->dst.output = ip6_pkt_discard_out;
960+
rt->dst.input = ip6_pkt_discard;
961+
break;
962+
}
963+
}
964+
965+
static void ip6_rt_init_dst(struct rt6_info *rt, struct rt6_info *ort)
966+
{
967+
if (ort->rt6i_flags & RTF_REJECT) {
968+
ip6_rt_init_dst_reject(rt, ort);
969+
return;
970+
}
971+
972+
rt->dst.error = 0;
973+
rt->dst.output = ip6_output;
974+
975+
if (ort->fib6_type == RTN_LOCAL) {
976+
rt->dst.flags |= DST_HOST;
977+
rt->dst.input = ip6_input;
978+
} else if (ipv6_addr_type(&ort->rt6i_dst.addr) & IPV6_ADDR_MULTICAST) {
979+
rt->dst.input = ip6_mc_input;
980+
} else {
981+
rt->dst.input = ip6_forward;
982+
}
983+
984+
if (ort->fib6_nh.nh_lwtstate) {
985+
rt->dst.lwtstate = lwtstate_get(ort->fib6_nh.nh_lwtstate);
986+
lwtunnel_set_redirect(&rt->dst);
987+
}
988+
989+
rt->dst.lastuse = jiffies;
990+
}
991+
923992
static void rt6_set_from(struct rt6_info *rt, struct rt6_info *from)
924993
{
925994
BUG_ON(from->from);
@@ -932,14 +1001,12 @@ static void rt6_set_from(struct rt6_info *rt, struct rt6_info *from)
9321001

9331002
static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort)
9341003
{
935-
rt->dst.input = ort->dst.input;
936-
rt->dst.output = ort->dst.output;
1004+
ip6_rt_init_dst(rt, ort);
1005+
9371006
rt->rt6i_dst = ort->rt6i_dst;
938-
rt->dst.error = ort->dst.error;
9391007
rt->rt6i_idev = ort->rt6i_idev;
9401008
if (rt->rt6i_idev)
9411009
in6_dev_hold(rt->rt6i_idev);
942-
rt->dst.lastuse = jiffies;
9431010
rt->rt6i_gateway = ort->fib6_nh.nh_gw;
9441011
rt->rt6i_flags = ort->rt6i_flags;
9451012
rt6_set_from(rt, ort);
@@ -2329,7 +2396,7 @@ static struct rt6_info *__ip6_route_redirect(struct net *net,
23292396
continue;
23302397
if (rt6_check_expired(rt))
23312398
continue;
2332-
if (rt->dst.error)
2399+
if (rt->rt6i_flags & RTF_REJECT)
23332400
break;
23342401
if (!(rt->rt6i_flags & RTF_GATEWAY))
23352402
continue;
@@ -2357,7 +2424,7 @@ static struct rt6_info *__ip6_route_redirect(struct net *net,
23572424

23582425
if (!rt)
23592426
rt = net->ipv6.ip6_null_entry;
2360-
else if (rt->dst.error) {
2427+
else if (rt->rt6i_flags & RTF_REJECT) {
23612428
rt = net->ipv6.ip6_null_entry;
23622429
goto out;
23632430
}
@@ -2900,15 +2967,6 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg,
29002967

29012968
addr_type = ipv6_addr_type(&cfg->fc_dst);
29022969

2903-
if (addr_type & IPV6_ADDR_MULTICAST)
2904-
rt->dst.input = ip6_mc_input;
2905-
else if (cfg->fc_flags & RTF_LOCAL)
2906-
rt->dst.input = ip6_input;
2907-
else
2908-
rt->dst.input = ip6_forward;
2909-
2910-
rt->dst.output = ip6_output;
2911-
29122970
if (cfg->fc_encap) {
29132971
struct lwtunnel_state *lwtstate;
29142972

@@ -2918,7 +2976,6 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg,
29182976
if (err)
29192977
goto out;
29202978
rt->fib6_nh.nh_lwtstate = lwtstate_get(lwtstate);
2921-
lwtunnel_set_redirect(&rt->dst);
29222979
}
29232980

29242981
ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len);
@@ -2958,27 +3015,6 @@ static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg,
29583015
}
29593016
}
29603017
rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP;
2961-
switch (cfg->fc_type) {
2962-
case RTN_BLACKHOLE:
2963-
rt->dst.error = -EINVAL;
2964-
rt->dst.output = dst_discard_out;
2965-
rt->dst.input = dst_discard;
2966-
break;
2967-
case RTN_PROHIBIT:
2968-
rt->dst.error = -EACCES;
2969-
rt->dst.output = ip6_pkt_prohibit_out;
2970-
rt->dst.input = ip6_pkt_prohibit;
2971-
break;
2972-
case RTN_THROW:
2973-
case RTN_UNREACHABLE:
2974-
default:
2975-
rt->dst.error = (cfg->fc_type == RTN_THROW) ? -EAGAIN
2976-
: (cfg->fc_type == RTN_UNREACHABLE)
2977-
? -EHOSTUNREACH : -ENETUNREACH;
2978-
rt->dst.output = ip6_pkt_discard_out;
2979-
rt->dst.input = ip6_pkt_discard;
2980-
break;
2981-
}
29823018
goto install_route;
29833019
}
29843020

@@ -3623,12 +3659,9 @@ struct rt6_info *addrconf_dst_alloc(struct net *net,
36233659
return ERR_PTR(-ENOMEM);
36243660

36253661
in6_dev_hold(idev);
3626-
3627-
rt->dst.flags |= DST_HOST;
3628-
rt->dst.input = ip6_input;
3629-
rt->dst.output = ip6_output;
36303662
rt->rt6i_idev = idev;
36313663

3664+
rt->dst.flags |= DST_HOST;
36323665
rt->rt6i_protocol = RTPROT_KERNEL;
36333666
rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
36343667
if (anycast) {

0 commit comments

Comments
 (0)