aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/ipv6/addrconf.c184
1 files changed, 109 insertions, 75 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 85100c1ac761..6913a82f4669 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -900,15 +900,95 @@ out:
900 goto out2; 900 goto out2;
901} 901}
902 902
903enum cleanup_prefix_rt_t {
904 CLEANUP_PREFIX_RT_NOP, /* no cleanup action for prefix route */
905 CLEANUP_PREFIX_RT_DEL, /* delete the prefix route */
906 CLEANUP_PREFIX_RT_EXPIRE, /* update the lifetime of the prefix route */
907};
908
909/*
910 * Check, whether the prefix for ifp would still need a prefix route
911 * after deleting ifp. The function returns one of the CLEANUP_PREFIX_RT_*
912 * constants.
913 *
914 * 1) we don't purge prefix if address was not permanent.
915 * prefix is managed by its own lifetime.
916 * 2) we also don't purge, if the address was IFA_F_NOPREFIXROUTE.
917 * 3) if there are no addresses, delete prefix.
918 * 4) if there are still other permanent address(es),
919 * corresponding prefix is still permanent.
920 * 5) if there are still other addresses with IFA_F_NOPREFIXROUTE,
921 * don't purge the prefix, assume user space is managing it.
922 * 6) otherwise, update prefix lifetime to the
923 * longest valid lifetime among the corresponding
924 * addresses on the device.
925 * Note: subsequent RA will update lifetime.
926 **/
927static enum cleanup_prefix_rt_t
928check_cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long *expires)
929{
930 struct inet6_ifaddr *ifa;
931 struct inet6_dev *idev = ifp->idev;
932 unsigned long lifetime;
933 enum cleanup_prefix_rt_t action = CLEANUP_PREFIX_RT_DEL;
934
935 *expires = jiffies;
936
937 list_for_each_entry(ifa, &idev->addr_list, if_list) {
938 if (ifa == ifp)
939 continue;
940 if (!ipv6_prefix_equal(&ifa->addr, &ifp->addr,
941 ifp->prefix_len))
942 continue;
943 if (ifa->flags & (IFA_F_PERMANENT | IFA_F_NOPREFIXROUTE))
944 return CLEANUP_PREFIX_RT_NOP;
945
946 action = CLEANUP_PREFIX_RT_EXPIRE;
947
948 spin_lock(&ifa->lock);
949
950 lifetime = addrconf_timeout_fixup(ifa->valid_lft, HZ);
951 /*
952 * Note: Because this address is
953 * not permanent, lifetime <
954 * LONG_MAX / HZ here.
955 */
956 if (time_before(*expires, ifa->tstamp + lifetime * HZ))
957 *expires = ifa->tstamp + lifetime * HZ;
958 spin_unlock(&ifa->lock);
959 }
960
961 return action;
962}
963
964static void
965cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires, bool del_rt)
966{
967 struct rt6_info *rt;
968
969 rt = addrconf_get_prefix_route(&ifp->addr,
970 ifp->prefix_len,
971 ifp->idev->dev,
972 0, RTF_GATEWAY | RTF_DEFAULT);
973 if (rt) {
974 if (del_rt)
975 ip6_del_rt(rt);
976 else {
977 if (!(rt->rt6i_flags & RTF_EXPIRES))
978 rt6_set_expires(rt, expires);
979 ip6_rt_put(rt);
980 }
981 }
982}
983
984
903/* This function wants to get referenced ifp and releases it before return */ 985/* This function wants to get referenced ifp and releases it before return */
904 986
905static void ipv6_del_addr(struct inet6_ifaddr *ifp) 987static void ipv6_del_addr(struct inet6_ifaddr *ifp)
906{ 988{
907 struct inet6_ifaddr *ifa, *ifn;
908 struct inet6_dev *idev = ifp->idev;
909 int state; 989 int state;
910 int deleted = 0, onlink = 0; 990 enum cleanup_prefix_rt_t action = CLEANUP_PREFIX_RT_NOP;
911 unsigned long expires = jiffies; 991 unsigned long expires;
912 992
913 spin_lock_bh(&ifp->state_lock); 993 spin_lock_bh(&ifp->state_lock);
914 state = ifp->state; 994 state = ifp->state;
@@ -922,7 +1002,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
922 hlist_del_init_rcu(&ifp->addr_lst); 1002 hlist_del_init_rcu(&ifp->addr_lst);
923 spin_unlock_bh(&addrconf_hash_lock); 1003 spin_unlock_bh(&addrconf_hash_lock);
924 1004
925 write_lock_bh(&idev->lock); 1005 write_lock_bh(&ifp->idev->lock);
926 1006
927 if (ifp->flags&IFA_F_TEMPORARY) { 1007 if (ifp->flags&IFA_F_TEMPORARY) {
928 list_del(&ifp->tmp_list); 1008 list_del(&ifp->tmp_list);
@@ -933,45 +1013,13 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
933 __in6_ifa_put(ifp); 1013 __in6_ifa_put(ifp);
934 } 1014 }
935 1015
936 list_for_each_entry_safe(ifa, ifn, &idev->addr_list, if_list) { 1016 if (ifp->flags & IFA_F_PERMANENT && !(ifp->flags & IFA_F_NOPREFIXROUTE))
937 if (ifa == ifp) { 1017 action = check_cleanup_prefix_route(ifp, &expires);
938 list_del_init(&ifp->if_list);
939 __in6_ifa_put(ifp);
940 1018
941 if (!(ifp->flags & IFA_F_PERMANENT) || onlink > 0) 1019 list_del_init(&ifp->if_list);
942 break; 1020 __in6_ifa_put(ifp);
943 deleted = 1; 1021
944 continue; 1022 write_unlock_bh(&ifp->idev->lock);
945 } else if (ifp->flags & IFA_F_PERMANENT) {
946 if (ipv6_prefix_equal(&ifa->addr, &ifp->addr,
947 ifp->prefix_len)) {
948 if (ifa->flags & IFA_F_PERMANENT) {
949 onlink = 1;
950 if (deleted)
951 break;
952 } else {
953 unsigned long lifetime;
954
955 if (!onlink)
956 onlink = -1;
957
958 spin_lock(&ifa->lock);
959
960 lifetime = addrconf_timeout_fixup(ifa->valid_lft, HZ);
961 /*
962 * Note: Because this address is
963 * not permanent, lifetime <
964 * LONG_MAX / HZ here.
965 */
966 if (time_before(expires,
967 ifa->tstamp + lifetime * HZ))
968 expires = ifa->tstamp + lifetime * HZ;
969 spin_unlock(&ifa->lock);
970 }
971 }
972 }
973 }
974 write_unlock_bh(&idev->lock);
975 1023
976 addrconf_del_dad_timer(ifp); 1024 addrconf_del_dad_timer(ifp);
977 1025
@@ -979,38 +1027,9 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
979 1027
980 inet6addr_notifier_call_chain(NETDEV_DOWN, ifp); 1028 inet6addr_notifier_call_chain(NETDEV_DOWN, ifp);
981 1029
982 /* 1030 if (action != CLEANUP_PREFIX_RT_NOP) {
983 * Purge or update corresponding prefix 1031 cleanup_prefix_route(ifp, expires,
984 * 1032 action == CLEANUP_PREFIX_RT_DEL);
985 * 1) we don't purge prefix here if address was not permanent.
986 * prefix is managed by its own lifetime.
987 * 2) if there are no addresses, delete prefix.
988 * 3) if there are still other permanent address(es),
989 * corresponding prefix is still permanent.
990 * 4) otherwise, update prefix lifetime to the
991 * longest valid lifetime among the corresponding
992 * addresses on the device.
993 * Note: subsequent RA will update lifetime.
994 *
995 * --yoshfuji
996 */
997 if ((ifp->flags & IFA_F_PERMANENT) && onlink < 1) {
998 struct rt6_info *rt;
999
1000 rt = addrconf_get_prefix_route(&ifp->addr,
1001 ifp->prefix_len,
1002 ifp->idev->dev,
1003 0, RTF_GATEWAY | RTF_DEFAULT);
1004
1005 if (rt) {
1006 if (onlink == 0) {
1007 ip6_del_rt(rt);
1008 rt = NULL;
1009 } else if (!(rt->rt6i_flags & RTF_EXPIRES)) {
1010 rt6_set_expires(rt, expires);
1011 }
1012 }
1013 ip6_rt_put(rt);
1014 } 1033 }
1015 1034
1016 /* clean up prefsrc entries */ 1035 /* clean up prefsrc entries */
@@ -3636,6 +3655,7 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags,
3636 clock_t expires; 3655 clock_t expires;
3637 unsigned long timeout; 3656 unsigned long timeout;
3638 bool was_managetempaddr; 3657 bool was_managetempaddr;
3658 bool had_prefixroute;
3639 3659
3640 if (!valid_lft || (prefered_lft > valid_lft)) 3660 if (!valid_lft || (prefered_lft > valid_lft))
3641 return -EINVAL; 3661 return -EINVAL;
@@ -3664,6 +3684,8 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags,
3664 3684
3665 spin_lock_bh(&ifp->lock); 3685 spin_lock_bh(&ifp->lock);
3666 was_managetempaddr = ifp->flags & IFA_F_MANAGETEMPADDR; 3686 was_managetempaddr = ifp->flags & IFA_F_MANAGETEMPADDR;
3687 had_prefixroute = ifp->flags & IFA_F_PERMANENT &&
3688 !(ifp->flags & IFA_F_NOPREFIXROUTE);
3667 ifp->flags &= ~(IFA_F_DEPRECATED | IFA_F_PERMANENT | IFA_F_NODAD | 3689 ifp->flags &= ~(IFA_F_DEPRECATED | IFA_F_PERMANENT | IFA_F_NODAD |
3668 IFA_F_HOMEADDRESS | IFA_F_MANAGETEMPADDR | 3690 IFA_F_HOMEADDRESS | IFA_F_MANAGETEMPADDR |
3669 IFA_F_NOPREFIXROUTE); 3691 IFA_F_NOPREFIXROUTE);
@@ -3679,6 +3701,18 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags,
3679 if (!(ifa_flags & IFA_F_NOPREFIXROUTE)) { 3701 if (!(ifa_flags & IFA_F_NOPREFIXROUTE)) {
3680 addrconf_prefix_route(&ifp->addr, ifp->prefix_len, ifp->idev->dev, 3702 addrconf_prefix_route(&ifp->addr, ifp->prefix_len, ifp->idev->dev,
3681 expires, flags); 3703 expires, flags);
3704 } else if (had_prefixroute) {
3705 enum cleanup_prefix_rt_t action;
3706 unsigned long rt_expires;
3707
3708 write_lock_bh(&ifp->idev->lock);
3709 action = check_cleanup_prefix_route(ifp, &rt_expires);
3710 write_unlock_bh(&ifp->idev->lock);
3711
3712 if (action != CLEANUP_PREFIX_RT_NOP) {
3713 cleanup_prefix_route(ifp, rt_expires,
3714 action == CLEANUP_PREFIX_RT_DEL);
3715 }
3682 } 3716 }
3683 3717
3684 if (was_managetempaddr || ifp->flags & IFA_F_MANAGETEMPADDR) { 3718 if (was_managetempaddr || ifp->flags & IFA_F_MANAGETEMPADDR) {