@@ -525,15 +525,17 @@ static void rt6_probe(struct fib6_info *rt)
525525 rcu_read_lock_bh ();
526526 neigh = __ipv6_neigh_lookup_noref (dev , nh_gw );
527527 if (neigh ) {
528+ struct inet6_dev * idev ;
529+
528530 if (neigh -> nud_state & NUD_VALID )
529531 goto out ;
530532
533+ idev = __in6_dev_get (dev );
531534 work = NULL ;
532535 write_lock (& neigh -> lock );
533536 if (!(neigh -> nud_state & NUD_VALID ) &&
534537 time_after (jiffies ,
535- neigh -> updated +
536- rt -> fib6_idev -> cnf .rtr_probe_interval )) {
538+ neigh -> updated + idev -> cnf .rtr_probe_interval )) {
537539 work = kmalloc (sizeof (* work ), GFP_ATOMIC );
538540 if (work )
539541 __neigh_set_probe_once (neigh );
@@ -622,18 +624,32 @@ static int rt6_score_route(struct fib6_info *rt, int oif, int strict)
622624 return m ;
623625}
624626
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+
625642static struct fib6_info * find_match (struct fib6_info * rt , int oif , int strict ,
626643 int * mpri , struct fib6_info * match ,
627644 bool * do_rr )
628645{
629646 int m ;
630647 bool match_do_rr = false;
631- struct inet6_dev * idev = rt -> fib6_idev ;
632648
633649 if (rt -> fib6_nh .nh_flags & RTNH_F_DEAD )
634650 goto out ;
635651
636- if (idev -> cnf . ignore_routes_with_linkdown &&
652+ if (fib6_ignore_linkdown ( rt ) &&
637653 rt -> fib6_nh .nh_flags & RTNH_F_LINKDOWN &&
638654 !(strict & RT6_LOOKUP_F_IGNORE_LINKSTATE ))
639655 goto out ;
@@ -957,12 +973,12 @@ static void rt6_set_from(struct rt6_info *rt, struct fib6_info *from)
957973
958974static void ip6_rt_copy_init (struct rt6_info * rt , struct fib6_info * ort )
959975{
976+ struct net_device * dev = fib6_info_nh_dev (ort );
977+
960978 ip6_rt_init_dst (rt , ort );
961979
962980 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 ;
966982 rt -> rt6i_gateway = ort -> fib6_nh .nh_gw ;
967983 rt -> rt6i_flags = ort -> fib6_flags ;
968984 rt6_set_from (rt , ort );
@@ -1355,7 +1371,18 @@ static unsigned int fib6_mtu(const struct fib6_info *rt)
13551371{
13561372 unsigned int mtu ;
13571373
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+
13591386 mtu = min_t (unsigned int , mtu , IP6_MAX_MTU );
13601387
13611388 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,
29853012 rt -> fib6_nh .nh_flags |= RTNH_F_LINKDOWN ;
29863013 rt -> fib6_nh .nh_flags |= (cfg -> fc_flags & RTNH_F_ONLINK );
29873014 rt -> fib6_nh .nh_dev = dev ;
2988- rt -> fib6_idev = idev ;
29893015 rt -> fib6_table = table ;
29903016
29913017 cfg -> fc_nlinfo .nl_net = dev_net (dev );
29923018
3019+ if (idev )
3020+ in6_dev_put (idev );
3021+
29933022 return rt ;
29943023out :
29953024 if (dev )
@@ -3425,8 +3454,11 @@ static void __rt6_purge_dflt_routers(struct net *net,
34253454restart :
34263455 rcu_read_lock ();
34273456 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+
34283460 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 )) {
34303462 fib6_info_hold (rt );
34313463 rcu_read_unlock ();
34323464 ip6_del_rt (net , rt );
@@ -3585,10 +3617,6 @@ struct fib6_info *addrconf_f6i_alloc(struct net *net,
35853617 return ERR_PTR (- ENOMEM );
35863618
35873619 f6i -> dst_nocount = true;
3588-
3589- in6_dev_hold (idev );
3590- f6i -> fib6_idev = idev ;
3591-
35923620 f6i -> dst_host = true;
35933621 f6i -> fib6_protocol = RTPROT_KERNEL ;
35943622 f6i -> fib6_flags = RTF_UP | RTF_NONEXTHOP ;
@@ -3706,7 +3734,7 @@ static bool rt6_is_dead(const struct fib6_info *rt)
37063734{
37073735 if (rt -> fib6_nh .nh_flags & RTNH_F_DEAD ||
37083736 (rt -> fib6_nh .nh_flags & RTNH_F_LINKDOWN &&
3709- rt -> fib6_idev -> cnf . ignore_routes_with_linkdown ))
3737+ fib6_ignore_linkdown ( rt ) ))
37103738 return true;
37113739
37123740 return false;
@@ -4424,8 +4452,11 @@ static int rt6_nexthop_info(struct sk_buff *skb, struct fib6_info *rt,
44244452
44254453 if (rt -> fib6_nh .nh_flags & RTNH_F_LINKDOWN ) {
44264454 * 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 ))
44284458 * flags |= RTNH_F_DEAD ;
4459+ rcu_read_unlock ();
44294460 }
44304461
44314462 if (rt -> fib6_flags & RTF_GATEWAY ) {
@@ -4800,7 +4831,6 @@ static int ip6_route_dev_notify(struct notifier_block *this,
48004831
48014832 if (event == NETDEV_REGISTER ) {
48024833 net -> ipv6 .fib6_null_entry -> fib6_nh .nh_dev = dev ;
4803- net -> ipv6 .fib6_null_entry -> fib6_idev = in6_dev_get (dev );
48044834 net -> ipv6 .ip6_null_entry -> dst .dev = dev ;
48054835 net -> ipv6 .ip6_null_entry -> rt6i_idev = in6_dev_get (dev );
48064836#ifdef CONFIG_IPV6_MULTIPLE_TABLES
@@ -4814,7 +4844,6 @@ static int ip6_route_dev_notify(struct notifier_block *this,
48144844 /* NETDEV_UNREGISTER could be fired for multiple times by
48154845 * netdev_wait_allrefs(). Make sure we only call this once.
48164846 */
4817- in6_dev_put_clear (& net -> ipv6 .fib6_null_entry -> fib6_idev );
48184847 in6_dev_put_clear (& net -> ipv6 .ip6_null_entry -> rt6i_idev );
48194848#ifdef CONFIG_IPV6_MULTIPLE_TABLES
48204849 in6_dev_put_clear (& net -> ipv6 .ip6_prohibit_entry -> rt6i_idev );
@@ -5137,7 +5166,6 @@ void __init ip6_route_init_special_entries(void)
51375166 * the loopback reference in rt6_info will not be taken, do it
51385167 * manually for init_net */
51395168 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 );
51415169 init_net .ipv6 .ip6_null_entry -> dst .dev = init_net .loopback_dev ;
51425170 init_net .ipv6 .ip6_null_entry -> rt6i_idev = in6_dev_get (init_net .loopback_dev );
51435171 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
0 commit comments