aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2014-01-15 09:36:59 -0500
committerDavid S. Miller <davem@davemloft.net>2014-01-15 20:00:40 -0500
commit5b84efecb7d939d06790b7bace5e513537d0767c (patch)
treea1487e383ad39c19412bd2c3c3fa3a91f4f3963a /net/ipv6
parent761aac737eb11901c382a3f021dead59a26983fc (diff)
ipv6 addrconf: don't cleanup prefix route for IFA_F_NOPREFIXROUTE
Refactor the deletion/update of prefix routes when removing an address. Now also consider IFA_F_NOPREFIXROUTE and if there is an address present with this flag, to not cleanup the route. Instead, assume that userspace is taking care of this route. Also perform the same cleanup, when userspace changes an existing address to add NOPREFIXROUTE (to an address that didn't have this flag). This is done because when the address was added, a prefix route was created for it. Since the user now wants to handle this route by himself, we cleanup this route. This cleanup of the route is not totally robust. There is no guarantee, that the route we are about to delete was really the one added by the kernel. This behavior does not change by the patch, and in practice it should work just fine. Signed-off-by: Thomas Haller <thaller@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-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) {