@@ -1013,8 +1013,8 @@ static void rt6_set_from(struct rt6_info *rt, struct rt6_info *from)
1013
1013
BUG_ON (from -> from );
1014
1014
1015
1015
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 ;
1018
1018
dst_init_metrics (& rt -> dst , from -> fib6_metrics -> metrics , true);
1019
1019
if (from -> fib6_metrics != & dst_default_metrics ) {
1020
1020
rt -> dst ._metrics |= DST_METRICS_REFCOUNTED ;
@@ -1097,45 +1097,46 @@ static struct rt6_info *ip6_pol_route_lookup(struct net *net,
1097
1097
const struct sk_buff * skb ,
1098
1098
int flags )
1099
1099
{
1100
- struct rt6_info * rt , * rt_cache ;
1100
+ struct rt6_info * f6i ;
1101
1101
struct fib6_node * fn ;
1102
+ struct rt6_info * rt ;
1102
1103
1103
1104
if (fl6 -> flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF )
1104
1105
flags &= ~RT6_LOOKUP_F_IFACE ;
1105
1106
1106
1107
rcu_read_lock ();
1107
1108
fn = fib6_lookup (& table -> tb6_root , & fl6 -> daddr , & fl6 -> saddr );
1108
1109
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 ;
1112
1113
} else {
1113
- rt = rt6_device_match (net , rt , & fl6 -> saddr ,
1114
+ f6i = rt6_device_match (net , f6i , & fl6 -> saddr ,
1114
1115
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 );
1118
1119
}
1119
- if (rt == net -> ipv6 .fib6_null_entry ) {
1120
+ if (f6i == net -> ipv6 .fib6_null_entry ) {
1120
1121
fn = fib6_backtrack (fn , & fl6 -> saddr );
1121
1122
if (fn )
1122
1123
goto restart ;
1123
1124
}
1125
+
1124
1126
/* 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 ) {
1128
1129
if (ip6_hold_safe (net , & rt , true))
1129
1130
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 ) {
1137
1132
rt = net -> ipv6 .ip6_null_entry ;
1138
1133
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
+ }
1139
1140
}
1140
1141
1141
1142
rcu_read_unlock ();
@@ -1218,9 +1219,6 @@ static struct rt6_info *ip6_rt_cache_alloc(struct rt6_info *ort,
1218
1219
* Clone the route.
1219
1220
*/
1220
1221
1221
- if (ort -> rt6i_flags & (RTF_CACHE | RTF_PCPU ))
1222
- ort = ort -> from ;
1223
-
1224
1222
rcu_read_lock ();
1225
1223
dev = ip6_rt_get_dev_rcu (ort );
1226
1224
rt = __ip6_dst_alloc (dev_net (dev ), dev , 0 );
@@ -1446,11 +1444,6 @@ static int rt6_insert_exception(struct rt6_info *nrt,
1446
1444
struct rt6_exception * rt6_ex ;
1447
1445
int err = 0 ;
1448
1446
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
-
1454
1447
spin_lock_bh (& rt6_exception_lock );
1455
1448
1456
1449
if (ort -> exception_bucket_flushed ) {
@@ -1589,7 +1582,7 @@ static struct rt6_info *rt6_find_cached_rt(struct rt6_info *rt,
1589
1582
}
1590
1583
1591
1584
/* 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 )
1593
1586
{
1594
1587
struct rt6_exception_bucket * bucket ;
1595
1588
struct rt6_info * from = rt -> from ;
@@ -1854,7 +1847,8 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
1854
1847
const struct sk_buff * skb , int flags )
1855
1848
{
1856
1849
struct fib6_node * fn , * saved_fn ;
1857
- struct rt6_info * rt , * rt_cache ;
1850
+ struct rt6_info * f6i ;
1851
+ struct rt6_info * rt ;
1858
1852
int strict = 0 ;
1859
1853
1860
1854
strict |= flags & RT6_LOOKUP_F_IFACE ;
@@ -1871,10 +1865,10 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
1871
1865
oif = 0 ;
1872
1866
1873
1867
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 ) {
1878
1872
fn = fib6_backtrack (fn , & fl6 -> saddr );
1879
1873
if (fn )
1880
1874
goto redo_rt6_select ;
@@ -1886,26 +1880,25 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
1886
1880
}
1887
1881
}
1888
1882
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 ) {
1895
1884
rt = net -> ipv6 .ip6_null_entry ;
1896
1885
rcu_read_unlock ();
1897
1886
dst_hold (& rt -> dst );
1898
1887
trace_fib6_table_lookup (net , rt , table , fl6 );
1899
1888
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 ) {
1901
1894
if (ip6_hold_safe (net , & rt , true))
1902
1895
dst_use_noref (& rt -> dst , jiffies );
1903
1896
1904
1897
rcu_read_unlock ();
1905
1898
trace_fib6_table_lookup (net , rt , table , fl6 );
1906
1899
return rt ;
1907
1900
} else if (unlikely ((fl6 -> flowi6_flags & FLOWI_FLAG_KNOWN_NH ) &&
1908
- !(rt -> rt6i_flags & RTF_GATEWAY ))) {
1901
+ !(f6i -> rt6i_flags & RTF_GATEWAY ))) {
1909
1902
/* Create a RTF_CACHE clone which will not be
1910
1903
* owned by the fib6 tree. It is for the special case where
1911
1904
* 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,
1914
1907
1915
1908
struct rt6_info * uncached_rt ;
1916
1909
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 );
1919
1912
} else {
1920
1913
rcu_read_unlock ();
1921
- uncached_rt = rt ;
1914
+ uncached_rt = f6i ;
1922
1915
goto uncached_rt_out ;
1923
1916
}
1924
1917
rcu_read_unlock ();
1925
1918
1926
- uncached_rt = ip6_rt_cache_alloc (rt , & fl6 -> daddr , NULL );
1919
+ uncached_rt = ip6_rt_cache_alloc (f6i , & fl6 -> daddr , NULL );
1927
1920
dst_release (& rt -> dst );
1928
1921
1929
1922
if (uncached_rt ) {
@@ -1946,18 +1939,18 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
1946
1939
1947
1940
struct rt6_info * pcpu_rt ;
1948
1941
1949
- dst_use_noref (& rt -> dst , jiffies );
1942
+ dst_use_noref (& f6i -> dst , jiffies );
1950
1943
local_bh_disable ();
1951
- pcpu_rt = rt6_get_pcpu_route (rt );
1944
+ pcpu_rt = rt6_get_pcpu_route (f6i );
1952
1945
1953
1946
if (!pcpu_rt ) {
1954
1947
/* 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 )) {
1956
1949
/* No dst_hold() on rt is needed because grabbing
1957
1950
* rt->rt6i_ref makes sure rt can't be released.
1958
1951
*/
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 );
1961
1954
} else {
1962
1955
/* rt is already removed from tree */
1963
1956
pcpu_rt = net -> ipv6 .ip6_null_entry ;
@@ -2419,7 +2412,8 @@ static struct rt6_info *__ip6_route_redirect(struct net *net,
2419
2412
int flags )
2420
2413
{
2421
2414
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 ;
2423
2417
struct fib6_node * fn ;
2424
2418
2425
2419
/* Get the "current" route for this destination and
@@ -2458,7 +2452,7 @@ static struct rt6_info *__ip6_route_redirect(struct net *net,
2458
2452
if (rt_cache &&
2459
2453
ipv6_addr_equal (& rdfl -> gateway ,
2460
2454
& rt_cache -> rt6i_gateway )) {
2461
- rt = rt_cache ;
2455
+ ret = rt_cache ;
2462
2456
break ;
2463
2457
}
2464
2458
continue ;
@@ -2469,7 +2463,7 @@ static struct rt6_info *__ip6_route_redirect(struct net *net,
2469
2463
if (!rt )
2470
2464
rt = net -> ipv6 .fib6_null_entry ;
2471
2465
else if (rt -> rt6i_flags & RTF_REJECT ) {
2472
- rt = net -> ipv6 .ip6_null_entry ;
2466
+ ret = net -> ipv6 .ip6_null_entry ;
2473
2467
goto out ;
2474
2468
}
2475
2469
@@ -2480,12 +2474,15 @@ static struct rt6_info *__ip6_route_redirect(struct net *net,
2480
2474
}
2481
2475
2482
2476
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 );
2484
2481
2485
2482
rcu_read_unlock ();
2486
2483
2487
- trace_fib6_table_lookup (net , rt , table , fl6 );
2488
- return rt ;
2484
+ trace_fib6_table_lookup (net , ret , table , fl6 );
2485
+ return ret ;
2489
2486
};
2490
2487
2491
2488
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)
3182
3179
return err ;
3183
3180
}
3184
3181
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
+
3185
3198
static int ip6_route_del (struct fib6_config * cfg ,
3186
3199
struct netlink_ext_ack * extack )
3187
3200
{
@@ -3206,11 +3219,16 @@ static int ip6_route_del(struct fib6_config *cfg,
3206
3219
if (fn ) {
3207
3220
for_each_fib6_node_rt_rcu (fn ) {
3208
3221
if (cfg -> fc_flags & RTF_CACHE ) {
3222
+ int rc ;
3223
+
3209
3224
rt_cache = rt6_find_cached_rt (rt , & cfg -> fc_dst ,
3210
3225
& 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 ;
3214
3232
}
3215
3233
if (cfg -> fc_ifindex &&
3216
3234
(!rt -> fib6_nh .nh_dev ||
@@ -3327,7 +3345,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
3327
3345
NEIGH_UPDATE_F_ISROUTER )),
3328
3346
NDISC_REDIRECT , & ndopts );
3329
3347
3330
- nrt = ip6_rt_cache_alloc (rt , & msg -> dest , NULL );
3348
+ nrt = ip6_rt_cache_alloc (rt -> from , & msg -> dest , NULL );
3331
3349
if (!nrt )
3332
3350
goto out ;
3333
3351
0 commit comments