Skip to content

Commit 23fb93a

Browse files
dsaherndavem330
authored andcommitted
net/ipv6: Cleanup exception and cache route handling
IPv6 FIB will only contain FIB entries with exception routes added to the FIB entry. Once this transformation is complete, FIB lookups will return a fib6_info with the lookup functions still returning a dst based rt6_info. The current code uses rt6_info for both paths and overloads the rt6_info variable usually called 'rt'. This patch introduces a new 'f6i' variable name for the result of the FIB lookup and keeps 'rt' as the dst based return variable. 'f6i' becomes a fib6_info in a later patch which is why it is introduced as f6i now; avoids the additional churn in the later patch. In addition, remove RTF_CACHE and dst checks from fib6 add and delete since they can not happen now and will never happen after the data type flip. Signed-off-by: David Ahern <dsahern@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent acb54e3 commit 23fb93a

File tree

3 files changed

+81
-78
lines changed

3 files changed

+81
-78
lines changed

include/net/ip6_route.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,6 @@ int ip6_ins_rt(struct net *net, struct rt6_info *rt);
106106
int ip6_del_rt(struct net *net, struct rt6_info *rt);
107107

108108
void rt6_flush_exceptions(struct rt6_info *rt);
109-
int rt6_remove_exception_rt(struct rt6_info *rt);
110109
void rt6_age_exceptions(struct rt6_info *rt, struct fib6_gc_args *gc_args,
111110
unsigned long now);
112111

net/ipv6/ip6_fib.c

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,7 +1074,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
10741074
static void fib6_start_gc(struct net *net, struct rt6_info *rt)
10751075
{
10761076
if (!timer_pending(&net->ipv6.ip6_fib_timer) &&
1077-
(rt->rt6i_flags & (RTF_EXPIRES | RTF_CACHE)))
1077+
(rt->rt6i_flags & RTF_EXPIRES))
10781078
mod_timer(&net->ipv6.ip6_fib_timer,
10791079
jiffies + net->ipv6.sysctl.ip6_rt_gc_interval);
10801080
}
@@ -1125,8 +1125,6 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt,
11251125

11261126
if (WARN_ON_ONCE(!atomic_read(&rt->dst.__refcnt)))
11271127
return -EINVAL;
1128-
if (WARN_ON_ONCE(rt->rt6i_flags & RTF_CACHE))
1129-
return -EINVAL;
11301128

11311129
if (info->nlh) {
11321130
if (!(info->nlh->nlmsg_flags & NLM_F_CREATE))
@@ -1650,8 +1648,6 @@ static void fib6_del_route(struct fib6_table *table, struct fib6_node *fn,
16501648

16511649
RT6_TRACE("fib6_del_route\n");
16521650

1653-
WARN_ON_ONCE(rt->rt6i_flags & RTF_CACHE);
1654-
16551651
/* Unlink it */
16561652
*rtp = rt->rt6_next;
16571653
rt->rt6i_node = NULL;
@@ -1720,21 +1716,11 @@ int fib6_del(struct rt6_info *rt, struct nl_info *info)
17201716
struct rt6_info __rcu **rtp;
17211717
struct rt6_info __rcu **rtp_next;
17221718

1723-
#if RT6_DEBUG >= 2
1724-
if (rt->dst.obsolete > 0) {
1725-
WARN_ON(fn);
1726-
return -ENOENT;
1727-
}
1728-
#endif
17291719
if (!fn || rt == net->ipv6.fib6_null_entry)
17301720
return -ENOENT;
17311721

17321722
WARN_ON(!(fn->fn_flags & RTN_RTINFO));
17331723

1734-
/* remove cached dst from exception table */
1735-
if (rt->rt6i_flags & RTF_CACHE)
1736-
return rt6_remove_exception_rt(rt);
1737-
17381724
/*
17391725
* Walk the leaf entries looking for ourself
17401726
*/

net/ipv6/route.c

Lines changed: 80 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,8 +1013,8 @@ static void rt6_set_from(struct rt6_info *rt, struct rt6_info *from)
10131013
BUG_ON(from->from);
10141014

10151015
rt->rt6i_flags &= ~RTF_EXPIRES;
1016-
dst_hold(&from->dst);
1017-
rt->from = from;
1016+
if (dst_hold_safe(&from->dst))
1017+
rt->from = from;
10181018
dst_init_metrics(&rt->dst, from->fib6_metrics->metrics, true);
10191019
if (from->fib6_metrics != &dst_default_metrics) {
10201020
rt->dst._metrics |= DST_METRICS_REFCOUNTED;
@@ -1097,45 +1097,46 @@ static struct rt6_info *ip6_pol_route_lookup(struct net *net,
10971097
const struct sk_buff *skb,
10981098
int flags)
10991099
{
1100-
struct rt6_info *rt, *rt_cache;
1100+
struct rt6_info *f6i;
11011101
struct fib6_node *fn;
1102+
struct rt6_info *rt;
11021103

11031104
if (fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF)
11041105
flags &= ~RT6_LOOKUP_F_IFACE;
11051106

11061107
rcu_read_lock();
11071108
fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
11081109
restart:
1109-
rt = rcu_dereference(fn->leaf);
1110-
if (!rt) {
1111-
rt = net->ipv6.fib6_null_entry;
1110+
f6i = rcu_dereference(fn->leaf);
1111+
if (!f6i) {
1112+
f6i = net->ipv6.fib6_null_entry;
11121113
} else {
1113-
rt = rt6_device_match(net, rt, &fl6->saddr,
1114+
f6i = rt6_device_match(net, f6i, &fl6->saddr,
11141115
fl6->flowi6_oif, flags);
1115-
if (rt->rt6i_nsiblings && fl6->flowi6_oif == 0)
1116-
rt = rt6_multipath_select(net, rt, fl6, fl6->flowi6_oif,
1117-
skb, flags);
1116+
if (f6i->rt6i_nsiblings && fl6->flowi6_oif == 0)
1117+
f6i = rt6_multipath_select(net, f6i, fl6,
1118+
fl6->flowi6_oif, skb, flags);
11181119
}
1119-
if (rt == net->ipv6.fib6_null_entry) {
1120+
if (f6i == net->ipv6.fib6_null_entry) {
11201121
fn = fib6_backtrack(fn, &fl6->saddr);
11211122
if (fn)
11221123
goto restart;
11231124
}
1125+
11241126
/* Search through exception table */
1125-
rt_cache = rt6_find_cached_rt(rt, &fl6->daddr, &fl6->saddr);
1126-
if (rt_cache) {
1127-
rt = rt_cache;
1127+
rt = rt6_find_cached_rt(f6i, &fl6->daddr, &fl6->saddr);
1128+
if (rt) {
11281129
if (ip6_hold_safe(net, &rt, true))
11291130
dst_use_noref(&rt->dst, jiffies);
1130-
} else if (dst_hold_safe(&rt->dst)) {
1131-
struct rt6_info *nrt;
1132-
1133-
nrt = ip6_create_rt_rcu(rt);
1134-
dst_release(&rt->dst);
1135-
rt = nrt;
1136-
} else {
1131+
} else if (f6i == net->ipv6.fib6_null_entry) {
11371132
rt = net->ipv6.ip6_null_entry;
11381133
dst_hold(&rt->dst);
1134+
} else {
1135+
rt = ip6_create_rt_rcu(f6i);
1136+
if (!rt) {
1137+
rt = net->ipv6.ip6_null_entry;
1138+
dst_hold(&rt->dst);
1139+
}
11391140
}
11401141

11411142
rcu_read_unlock();
@@ -1218,9 +1219,6 @@ static struct rt6_info *ip6_rt_cache_alloc(struct rt6_info *ort,
12181219
* Clone the route.
12191220
*/
12201221

1221-
if (ort->rt6i_flags & (RTF_CACHE | RTF_PCPU))
1222-
ort = ort->from;
1223-
12241222
rcu_read_lock();
12251223
dev = ip6_rt_get_dev_rcu(ort);
12261224
rt = __ip6_dst_alloc(dev_net(dev), dev, 0);
@@ -1446,11 +1444,6 @@ static int rt6_insert_exception(struct rt6_info *nrt,
14461444
struct rt6_exception *rt6_ex;
14471445
int err = 0;
14481446

1449-
/* ort can't be a cache or pcpu route */
1450-
if (ort->rt6i_flags & (RTF_CACHE | RTF_PCPU))
1451-
ort = ort->from;
1452-
WARN_ON_ONCE(ort->rt6i_flags & (RTF_CACHE | RTF_PCPU));
1453-
14541447
spin_lock_bh(&rt6_exception_lock);
14551448

14561449
if (ort->exception_bucket_flushed) {
@@ -1589,7 +1582,7 @@ static struct rt6_info *rt6_find_cached_rt(struct rt6_info *rt,
15891582
}
15901583

15911584
/* Remove the passed in cached rt from the hash table that contains it */
1592-
int rt6_remove_exception_rt(struct rt6_info *rt)
1585+
static int rt6_remove_exception_rt(struct rt6_info *rt)
15931586
{
15941587
struct rt6_exception_bucket *bucket;
15951588
struct rt6_info *from = rt->from;
@@ -1854,7 +1847,8 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
18541847
const struct sk_buff *skb, int flags)
18551848
{
18561849
struct fib6_node *fn, *saved_fn;
1857-
struct rt6_info *rt, *rt_cache;
1850+
struct rt6_info *f6i;
1851+
struct rt6_info *rt;
18581852
int strict = 0;
18591853

18601854
strict |= flags & RT6_LOOKUP_F_IFACE;
@@ -1871,10 +1865,10 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
18711865
oif = 0;
18721866

18731867
redo_rt6_select:
1874-
rt = rt6_select(net, fn, oif, strict);
1875-
if (rt->rt6i_nsiblings)
1876-
rt = rt6_multipath_select(net, rt, fl6, oif, skb, strict);
1877-
if (rt == net->ipv6.fib6_null_entry) {
1868+
f6i = rt6_select(net, fn, oif, strict);
1869+
if (f6i->rt6i_nsiblings)
1870+
f6i = rt6_multipath_select(net, f6i, fl6, oif, skb, strict);
1871+
if (f6i == net->ipv6.fib6_null_entry) {
18781872
fn = fib6_backtrack(fn, &fl6->saddr);
18791873
if (fn)
18801874
goto redo_rt6_select;
@@ -1886,26 +1880,25 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
18861880
}
18871881
}
18881882

1889-
/*Search through exception table */
1890-
rt_cache = rt6_find_cached_rt(rt, &fl6->daddr, &fl6->saddr);
1891-
if (rt_cache)
1892-
rt = rt_cache;
1893-
1894-
if (rt == net->ipv6.fib6_null_entry) {
1883+
if (f6i == net->ipv6.fib6_null_entry) {
18951884
rt = net->ipv6.ip6_null_entry;
18961885
rcu_read_unlock();
18971886
dst_hold(&rt->dst);
18981887
trace_fib6_table_lookup(net, rt, table, fl6);
18991888
return rt;
1900-
} else if (rt->rt6i_flags & RTF_CACHE) {
1889+
}
1890+
1891+
/*Search through exception table */
1892+
rt = rt6_find_cached_rt(f6i, &fl6->daddr, &fl6->saddr);
1893+
if (rt) {
19011894
if (ip6_hold_safe(net, &rt, true))
19021895
dst_use_noref(&rt->dst, jiffies);
19031896

19041897
rcu_read_unlock();
19051898
trace_fib6_table_lookup(net, rt, table, fl6);
19061899
return rt;
19071900
} else if (unlikely((fl6->flowi6_flags & FLOWI_FLAG_KNOWN_NH) &&
1908-
!(rt->rt6i_flags & RTF_GATEWAY))) {
1901+
!(f6i->rt6i_flags & RTF_GATEWAY))) {
19091902
/* Create a RTF_CACHE clone which will not be
19101903
* owned by the fib6 tree. It is for the special case where
19111904
* the daddr in the skb during the neighbor look-up is different
@@ -1914,16 +1907,16 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
19141907

19151908
struct rt6_info *uncached_rt;
19161909

1917-
if (ip6_hold_safe(net, &rt, true)) {
1918-
dst_use_noref(&rt->dst, jiffies);
1910+
if (ip6_hold_safe(net, &f6i, true)) {
1911+
dst_use_noref(&f6i->dst, jiffies);
19191912
} else {
19201913
rcu_read_unlock();
1921-
uncached_rt = rt;
1914+
uncached_rt = f6i;
19221915
goto uncached_rt_out;
19231916
}
19241917
rcu_read_unlock();
19251918

1926-
uncached_rt = ip6_rt_cache_alloc(rt, &fl6->daddr, NULL);
1919+
uncached_rt = ip6_rt_cache_alloc(f6i, &fl6->daddr, NULL);
19271920
dst_release(&rt->dst);
19281921

19291922
if (uncached_rt) {
@@ -1946,18 +1939,18 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
19461939

19471940
struct rt6_info *pcpu_rt;
19481941

1949-
dst_use_noref(&rt->dst, jiffies);
1942+
dst_use_noref(&f6i->dst, jiffies);
19501943
local_bh_disable();
1951-
pcpu_rt = rt6_get_pcpu_route(rt);
1944+
pcpu_rt = rt6_get_pcpu_route(f6i);
19521945

19531946
if (!pcpu_rt) {
19541947
/* atomic_inc_not_zero() is needed when using rcu */
1955-
if (atomic_inc_not_zero(&rt->rt6i_ref)) {
1948+
if (atomic_inc_not_zero(&f6i->rt6i_ref)) {
19561949
/* No dst_hold() on rt is needed because grabbing
19571950
* rt->rt6i_ref makes sure rt can't be released.
19581951
*/
1959-
pcpu_rt = rt6_make_pcpu_route(net, rt);
1960-
rt6_release(rt);
1952+
pcpu_rt = rt6_make_pcpu_route(net, f6i);
1953+
rt6_release(f6i);
19611954
} else {
19621955
/* rt is already removed from tree */
19631956
pcpu_rt = net->ipv6.ip6_null_entry;
@@ -2419,7 +2412,8 @@ static struct rt6_info *__ip6_route_redirect(struct net *net,
24192412
int flags)
24202413
{
24212414
struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6;
2422-
struct rt6_info *rt, *rt_cache;
2415+
struct rt6_info *ret = NULL, *rt_cache;
2416+
struct rt6_info *rt;
24232417
struct fib6_node *fn;
24242418

24252419
/* Get the "current" route for this destination and
@@ -2458,7 +2452,7 @@ static struct rt6_info *__ip6_route_redirect(struct net *net,
24582452
if (rt_cache &&
24592453
ipv6_addr_equal(&rdfl->gateway,
24602454
&rt_cache->rt6i_gateway)) {
2461-
rt = rt_cache;
2455+
ret = rt_cache;
24622456
break;
24632457
}
24642458
continue;
@@ -2469,7 +2463,7 @@ static struct rt6_info *__ip6_route_redirect(struct net *net,
24692463
if (!rt)
24702464
rt = net->ipv6.fib6_null_entry;
24712465
else if (rt->rt6i_flags & RTF_REJECT) {
2472-
rt = net->ipv6.ip6_null_entry;
2466+
ret = net->ipv6.ip6_null_entry;
24732467
goto out;
24742468
}
24752469

@@ -2480,12 +2474,15 @@ static struct rt6_info *__ip6_route_redirect(struct net *net,
24802474
}
24812475

24822476
out:
2483-
ip6_hold_safe(net, &rt, true);
2477+
if (ret)
2478+
dst_hold(&ret->dst);
2479+
else
2480+
ret = ip6_create_rt_rcu(rt);
24842481

24852482
rcu_read_unlock();
24862483

2487-
trace_fib6_table_lookup(net, rt, table, fl6);
2488-
return rt;
2484+
trace_fib6_table_lookup(net, ret, table, fl6);
2485+
return ret;
24892486
};
24902487

24912488
static struct dst_entry *ip6_route_redirect(struct net *net,
@@ -3182,6 +3179,22 @@ static int __ip6_del_rt_siblings(struct rt6_info *rt, struct fib6_config *cfg)
31823179
return err;
31833180
}
31843181

3182+
static int ip6_del_cached_rt(struct rt6_info *rt, struct fib6_config *cfg)
3183+
{
3184+
int rc = -ESRCH;
3185+
3186+
if (cfg->fc_ifindex && rt->dst.dev->ifindex != cfg->fc_ifindex)
3187+
goto out;
3188+
3189+
if (cfg->fc_flags & RTF_GATEWAY &&
3190+
!ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
3191+
goto out;
3192+
if (dst_hold_safe(&rt->dst))
3193+
rc = rt6_remove_exception_rt(rt);
3194+
out:
3195+
return rc;
3196+
}
3197+
31853198
static int ip6_route_del(struct fib6_config *cfg,
31863199
struct netlink_ext_ack *extack)
31873200
{
@@ -3206,11 +3219,16 @@ static int ip6_route_del(struct fib6_config *cfg,
32063219
if (fn) {
32073220
for_each_fib6_node_rt_rcu(fn) {
32083221
if (cfg->fc_flags & RTF_CACHE) {
3222+
int rc;
3223+
32093224
rt_cache = rt6_find_cached_rt(rt, &cfg->fc_dst,
32103225
&cfg->fc_src);
3211-
if (!rt_cache)
3212-
continue;
3213-
rt = rt_cache;
3226+
if (rt_cache) {
3227+
rc = ip6_del_cached_rt(rt_cache, cfg);
3228+
if (rc != -ESRCH)
3229+
return rc;
3230+
}
3231+
continue;
32143232
}
32153233
if (cfg->fc_ifindex &&
32163234
(!rt->fib6_nh.nh_dev ||
@@ -3327,7 +3345,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
33273345
NEIGH_UPDATE_F_ISROUTER)),
33283346
NDISC_REDIRECT, &ndopts);
33293347

3330-
nrt = ip6_rt_cache_alloc(rt, &msg->dest, NULL);
3348+
nrt = ip6_rt_cache_alloc(rt->from, &msg->dest, NULL);
33313349
if (!nrt)
33323350
goto out;
33333351

0 commit comments

Comments
 (0)