@@ -525,15 +525,17 @@ static void rt6_probe(struct fib6_info *rt)
525
525
rcu_read_lock_bh ();
526
526
neigh = __ipv6_neigh_lookup_noref (dev , nh_gw );
527
527
if (neigh ) {
528
+ struct inet6_dev * idev ;
529
+
528
530
if (neigh -> nud_state & NUD_VALID )
529
531
goto out ;
530
532
533
+ idev = __in6_dev_get (dev );
531
534
work = NULL ;
532
535
write_lock (& neigh -> lock );
533
536
if (!(neigh -> nud_state & NUD_VALID ) &&
534
537
time_after (jiffies ,
535
- neigh -> updated +
536
- rt -> fib6_idev -> cnf .rtr_probe_interval )) {
538
+ neigh -> updated + idev -> cnf .rtr_probe_interval )) {
537
539
work = kmalloc (sizeof (* work ), GFP_ATOMIC );
538
540
if (work )
539
541
__neigh_set_probe_once (neigh );
@@ -622,18 +624,32 @@ static int rt6_score_route(struct fib6_info *rt, int oif, int strict)
622
624
return m ;
623
625
}
624
626
627
+ /* called with rc_read_lock held */
628
+ static inline bool fib6_ignore_linkdown (const struct fib6_info * f6i )
629
+ {
630
+ const struct net_device * dev = fib6_info_nh_dev (f6i );
631
+ bool rc = false;
632
+
633
+ if (dev ) {
634
+ const struct inet6_dev * idev = __in6_dev_get (dev );
635
+
636
+ rc = !!idev -> cnf .ignore_routes_with_linkdown ;
637
+ }
638
+
639
+ return rc ;
640
+ }
641
+
625
642
static struct fib6_info * find_match (struct fib6_info * rt , int oif , int strict ,
626
643
int * mpri , struct fib6_info * match ,
627
644
bool * do_rr )
628
645
{
629
646
int m ;
630
647
bool match_do_rr = false;
631
- struct inet6_dev * idev = rt -> fib6_idev ;
632
648
633
649
if (rt -> fib6_nh .nh_flags & RTNH_F_DEAD )
634
650
goto out ;
635
651
636
- if (idev -> cnf . ignore_routes_with_linkdown &&
652
+ if (fib6_ignore_linkdown ( rt ) &&
637
653
rt -> fib6_nh .nh_flags & RTNH_F_LINKDOWN &&
638
654
!(strict & RT6_LOOKUP_F_IGNORE_LINKSTATE ))
639
655
goto out ;
@@ -957,12 +973,12 @@ static void rt6_set_from(struct rt6_info *rt, struct fib6_info *from)
957
973
958
974
static void ip6_rt_copy_init (struct rt6_info * rt , struct fib6_info * ort )
959
975
{
976
+ struct net_device * dev = fib6_info_nh_dev (ort );
977
+
960
978
ip6_rt_init_dst (rt , ort );
961
979
962
980
rt -> rt6i_dst = ort -> fib6_dst ;
963
- rt -> rt6i_idev = ort -> fib6_idev ;
964
- if (rt -> rt6i_idev )
965
- in6_dev_hold (rt -> rt6i_idev );
981
+ rt -> rt6i_idev = dev ? in6_dev_get (dev ) : NULL ;
966
982
rt -> rt6i_gateway = ort -> fib6_nh .nh_gw ;
967
983
rt -> rt6i_flags = ort -> fib6_flags ;
968
984
rt6_set_from (rt , ort );
@@ -1355,7 +1371,18 @@ static unsigned int fib6_mtu(const struct fib6_info *rt)
1355
1371
{
1356
1372
unsigned int mtu ;
1357
1373
1358
- mtu = rt -> fib6_pmtu ? : rt -> fib6_idev -> cnf .mtu6 ;
1374
+ if (rt -> fib6_pmtu ) {
1375
+ mtu = rt -> fib6_pmtu ;
1376
+ } else {
1377
+ struct net_device * dev = fib6_info_nh_dev (rt );
1378
+ struct inet6_dev * idev ;
1379
+
1380
+ rcu_read_lock ();
1381
+ idev = __in6_dev_get (dev );
1382
+ mtu = idev -> cnf .mtu6 ;
1383
+ rcu_read_unlock ();
1384
+ }
1385
+
1359
1386
mtu = min_t (unsigned int , mtu , IP6_MAX_MTU );
1360
1387
1361
1388
return mtu - lwtunnel_headroom (rt -> fib6_nh .nh_lwtstate , mtu );
@@ -2985,11 +3012,13 @@ static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg,
2985
3012
rt -> fib6_nh .nh_flags |= RTNH_F_LINKDOWN ;
2986
3013
rt -> fib6_nh .nh_flags |= (cfg -> fc_flags & RTNH_F_ONLINK );
2987
3014
rt -> fib6_nh .nh_dev = dev ;
2988
- rt -> fib6_idev = idev ;
2989
3015
rt -> fib6_table = table ;
2990
3016
2991
3017
cfg -> fc_nlinfo .nl_net = dev_net (dev );
2992
3018
3019
+ if (idev )
3020
+ in6_dev_put (idev );
3021
+
2993
3022
return rt ;
2994
3023
out :
2995
3024
if (dev )
@@ -3425,8 +3454,11 @@ static void __rt6_purge_dflt_routers(struct net *net,
3425
3454
restart :
3426
3455
rcu_read_lock ();
3427
3456
for_each_fib6_node_rt_rcu (& table -> tb6_root ) {
3457
+ struct net_device * dev = fib6_info_nh_dev (rt );
3458
+ struct inet6_dev * idev = dev ? __in6_dev_get (dev ) : NULL ;
3459
+
3428
3460
if (rt -> fib6_flags & (RTF_DEFAULT | RTF_ADDRCONF ) &&
3429
- (!rt -> fib6_idev || rt -> fib6_idev -> cnf .accept_ra != 2 )) {
3461
+ (!idev || idev -> cnf .accept_ra != 2 )) {
3430
3462
fib6_info_hold (rt );
3431
3463
rcu_read_unlock ();
3432
3464
ip6_del_rt (net , rt );
@@ -3585,10 +3617,6 @@ struct fib6_info *addrconf_f6i_alloc(struct net *net,
3585
3617
return ERR_PTR (- ENOMEM );
3586
3618
3587
3619
f6i -> dst_nocount = true;
3588
-
3589
- in6_dev_hold (idev );
3590
- f6i -> fib6_idev = idev ;
3591
-
3592
3620
f6i -> dst_host = true;
3593
3621
f6i -> fib6_protocol = RTPROT_KERNEL ;
3594
3622
f6i -> fib6_flags = RTF_UP | RTF_NONEXTHOP ;
@@ -3706,7 +3734,7 @@ static bool rt6_is_dead(const struct fib6_info *rt)
3706
3734
{
3707
3735
if (rt -> fib6_nh .nh_flags & RTNH_F_DEAD ||
3708
3736
(rt -> fib6_nh .nh_flags & RTNH_F_LINKDOWN &&
3709
- rt -> fib6_idev -> cnf . ignore_routes_with_linkdown ))
3737
+ fib6_ignore_linkdown ( rt ) ))
3710
3738
return true;
3711
3739
3712
3740
return false;
@@ -4424,8 +4452,11 @@ static int rt6_nexthop_info(struct sk_buff *skb, struct fib6_info *rt,
4424
4452
4425
4453
if (rt -> fib6_nh .nh_flags & RTNH_F_LINKDOWN ) {
4426
4454
* flags |= RTNH_F_LINKDOWN ;
4427
- if (rt -> fib6_idev -> cnf .ignore_routes_with_linkdown )
4455
+
4456
+ rcu_read_lock ();
4457
+ if (fib6_ignore_linkdown (rt ))
4428
4458
* flags |= RTNH_F_DEAD ;
4459
+ rcu_read_unlock ();
4429
4460
}
4430
4461
4431
4462
if (rt -> fib6_flags & RTF_GATEWAY ) {
@@ -4800,7 +4831,6 @@ static int ip6_route_dev_notify(struct notifier_block *this,
4800
4831
4801
4832
if (event == NETDEV_REGISTER ) {
4802
4833
net -> ipv6 .fib6_null_entry -> fib6_nh .nh_dev = dev ;
4803
- net -> ipv6 .fib6_null_entry -> fib6_idev = in6_dev_get (dev );
4804
4834
net -> ipv6 .ip6_null_entry -> dst .dev = dev ;
4805
4835
net -> ipv6 .ip6_null_entry -> rt6i_idev = in6_dev_get (dev );
4806
4836
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
@@ -4814,7 +4844,6 @@ static int ip6_route_dev_notify(struct notifier_block *this,
4814
4844
/* NETDEV_UNREGISTER could be fired for multiple times by
4815
4845
* netdev_wait_allrefs(). Make sure we only call this once.
4816
4846
*/
4817
- in6_dev_put_clear (& net -> ipv6 .fib6_null_entry -> fib6_idev );
4818
4847
in6_dev_put_clear (& net -> ipv6 .ip6_null_entry -> rt6i_idev );
4819
4848
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
4820
4849
in6_dev_put_clear (& net -> ipv6 .ip6_prohibit_entry -> rt6i_idev );
@@ -5137,7 +5166,6 @@ void __init ip6_route_init_special_entries(void)
5137
5166
* the loopback reference in rt6_info will not be taken, do it
5138
5167
* manually for init_net */
5139
5168
init_net .ipv6 .fib6_null_entry -> fib6_nh .nh_dev = init_net .loopback_dev ;
5140
- init_net .ipv6 .fib6_null_entry -> fib6_idev = in6_dev_get (init_net .loopback_dev );
5141
5169
init_net .ipv6 .ip6_null_entry -> dst .dev = init_net .loopback_dev ;
5142
5170
init_net .ipv6 .ip6_null_entry -> rt6i_idev = in6_dev_get (init_net .loopback_dev );
5143
5171
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
0 commit comments