aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/networking/ip-sysctl.txt9
-rw-r--r--include/linux/ipv6.h1
-rw-r--r--include/uapi/linux/ipv6.h1
-rw-r--r--net/ipv6/addrconf.c162
4 files changed, 12 insertions, 161 deletions
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index b183e2b606c8..e0ac25210f7c 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -1568,15 +1568,6 @@ temp_prefered_lft - INTEGER
1568 Preferred lifetime (in seconds) for temporary addresses. 1568 Preferred lifetime (in seconds) for temporary addresses.
1569 Default: 86400 (1 day) 1569 Default: 86400 (1 day)
1570 1570
1571keep_addr_on_down - INTEGER
1572 Keep all IPv6 addresses on an interface down event. If set static
1573 global addresses with no expiration time are not flushed.
1574 >0 : enabled
1575 0 : system default
1576 <0 : disabled
1577
1578 Default: 0 (addresses are removed)
1579
1580max_desync_factor - INTEGER 1571max_desync_factor - INTEGER
1581 Maximum value for DESYNC_FACTOR, which is a random value 1572 Maximum value for DESYNC_FACTOR, which is a random value
1582 that ensures that clients don't synchronize with each 1573 that ensures that clients don't synchronize with each
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 7edc14fb66b6..4b2267e1b7c3 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -62,7 +62,6 @@ struct ipv6_devconf {
62 struct in6_addr secret; 62 struct in6_addr secret;
63 } stable_secret; 63 } stable_secret;
64 __s32 use_oif_addrs_only; 64 __s32 use_oif_addrs_only;
65 __s32 keep_addr_on_down;
66 void *sysctl; 65 void *sysctl;
67}; 66};
68 67
diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h
index 395876060f50..ec117b65d5a5 100644
--- a/include/uapi/linux/ipv6.h
+++ b/include/uapi/linux/ipv6.h
@@ -176,7 +176,6 @@ enum {
176 DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN, 176 DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN,
177 DEVCONF_DROP_UNICAST_IN_L2_MULTICAST, 177 DEVCONF_DROP_UNICAST_IN_L2_MULTICAST,
178 DEVCONF_DROP_UNSOLICITED_NA, 178 DEVCONF_DROP_UNSOLICITED_NA,
179 DEVCONF_KEEP_ADDR_ON_DOWN,
180 DEVCONF_MAX 179 DEVCONF_MAX
181}; 180};
182 181
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 23cec53b568a..d77ba395d593 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -216,7 +216,6 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
216 }, 216 },
217 .use_oif_addrs_only = 0, 217 .use_oif_addrs_only = 0,
218 .ignore_routes_with_linkdown = 0, 218 .ignore_routes_with_linkdown = 0,
219 .keep_addr_on_down = 0,
220}; 219};
221 220
222static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { 221static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
@@ -261,7 +260,6 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
261 }, 260 },
262 .use_oif_addrs_only = 0, 261 .use_oif_addrs_only = 0,
263 .ignore_routes_with_linkdown = 0, 262 .ignore_routes_with_linkdown = 0,
264 .keep_addr_on_down = 0,
265}; 263};
266 264
267/* Check if a valid qdisc is available */ 265/* Check if a valid qdisc is available */
@@ -3176,81 +3174,6 @@ static void addrconf_gre_config(struct net_device *dev)
3176} 3174}
3177#endif 3175#endif
3178 3176
3179#if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV)
3180/* If the host route is cached on the addr struct make sure it is associated
3181 * with the proper table. e.g., enslavement can change and if so the cached
3182 * host route needs to move to the new table.
3183 */
3184static void l3mdev_check_host_rt(struct inet6_dev *idev,
3185 struct inet6_ifaddr *ifp)
3186{
3187 if (ifp->rt) {
3188 u32 tb_id = l3mdev_fib_table(idev->dev) ? : RT6_TABLE_LOCAL;
3189
3190 if (tb_id != ifp->rt->rt6i_table->tb6_id) {
3191 ip6_del_rt(ifp->rt);
3192 ifp->rt = NULL;
3193 }
3194 }
3195}
3196#else
3197static void l3mdev_check_host_rt(struct inet6_dev *idev,
3198 struct inet6_ifaddr *ifp)
3199{
3200}
3201#endif
3202
3203static int fixup_permanent_addr(struct inet6_dev *idev,
3204 struct inet6_ifaddr *ifp)
3205{
3206 l3mdev_check_host_rt(idev, ifp);
3207
3208 if (!ifp->rt) {
3209 struct rt6_info *rt;
3210
3211 rt = addrconf_dst_alloc(idev, &ifp->addr, false);
3212 if (unlikely(IS_ERR(rt)))
3213 return PTR_ERR(rt);
3214
3215 ifp->rt = rt;
3216 }
3217
3218 if (!(ifp->flags & IFA_F_NOPREFIXROUTE)) {
3219 addrconf_prefix_route(&ifp->addr, ifp->prefix_len,
3220 idev->dev, 0, 0);
3221 }
3222
3223 addrconf_dad_start(ifp);
3224
3225 return 0;
3226}
3227
3228static void addrconf_permanent_addr(struct net_device *dev)
3229{
3230 struct inet6_ifaddr *ifp, *tmp;
3231 struct inet6_dev *idev;
3232
3233 idev = __in6_dev_get(dev);
3234 if (!idev)
3235 return;
3236
3237 write_lock_bh(&idev->lock);
3238
3239 list_for_each_entry_safe(ifp, tmp, &idev->addr_list, if_list) {
3240 if ((ifp->flags & IFA_F_PERMANENT) &&
3241 fixup_permanent_addr(idev, ifp) < 0) {
3242 write_unlock_bh(&idev->lock);
3243 ipv6_del_addr(ifp);
3244 write_lock_bh(&idev->lock);
3245
3246 net_info_ratelimited("%s: Failed to add prefix route for address %pI6c; dropping\n",
3247 idev->dev->name, &ifp->addr);
3248 }
3249 }
3250
3251 write_unlock_bh(&idev->lock);
3252}
3253
3254static int addrconf_notify(struct notifier_block *this, unsigned long event, 3177static int addrconf_notify(struct notifier_block *this, unsigned long event,
3255 void *ptr) 3178 void *ptr)
3256{ 3179{
@@ -3337,9 +3260,6 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
3337 run_pending = 1; 3260 run_pending = 1;
3338 } 3261 }
3339 3262
3340 /* restore routes for permanent addresses */
3341 addrconf_permanent_addr(dev);
3342
3343 switch (dev->type) { 3263 switch (dev->type) {
3344#if IS_ENABLED(CONFIG_IPV6_SIT) 3264#if IS_ENABLED(CONFIG_IPV6_SIT)
3345 case ARPHRD_SIT: 3265 case ARPHRD_SIT:
@@ -3448,20 +3368,11 @@ static void addrconf_type_change(struct net_device *dev, unsigned long event)
3448 ipv6_mc_unmap(idev); 3368 ipv6_mc_unmap(idev);
3449} 3369}
3450 3370
3451static bool addr_is_local(const struct in6_addr *addr)
3452{
3453 return ipv6_addr_type(addr) &
3454 (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK);
3455}
3456
3457static int addrconf_ifdown(struct net_device *dev, int how) 3371static int addrconf_ifdown(struct net_device *dev, int how)
3458{ 3372{
3459 struct net *net = dev_net(dev); 3373 struct net *net = dev_net(dev);
3460 struct inet6_dev *idev; 3374 struct inet6_dev *idev;
3461 struct inet6_ifaddr *ifa, *tmp; 3375 struct inet6_ifaddr *ifa;
3462 struct list_head del_list;
3463 int _keep_addr;
3464 bool keep_addr;
3465 int state, i; 3376 int state, i;
3466 3377
3467 ASSERT_RTNL(); 3378 ASSERT_RTNL();
@@ -3488,16 +3399,6 @@ static int addrconf_ifdown(struct net_device *dev, int how)
3488 3399
3489 } 3400 }
3490 3401
3491 /* aggregate the system setting and interface setting */
3492 _keep_addr = net->ipv6.devconf_all->keep_addr_on_down;
3493 if (!_keep_addr)
3494 _keep_addr = idev->cnf.keep_addr_on_down;
3495
3496 /* combine the user config with event to determine if permanent
3497 * addresses are to be removed from address hash table
3498 */
3499 keep_addr = !(how || _keep_addr <= 0);
3500
3501 /* Step 2: clear hash table */ 3402 /* Step 2: clear hash table */
3502 for (i = 0; i < IN6_ADDR_HSIZE; i++) { 3403 for (i = 0; i < IN6_ADDR_HSIZE; i++) {
3503 struct hlist_head *h = &inet6_addr_lst[i]; 3404 struct hlist_head *h = &inet6_addr_lst[i];
@@ -3506,16 +3407,9 @@ static int addrconf_ifdown(struct net_device *dev, int how)
3506restart: 3407restart:
3507 hlist_for_each_entry_rcu(ifa, h, addr_lst) { 3408 hlist_for_each_entry_rcu(ifa, h, addr_lst) {
3508 if (ifa->idev == idev) { 3409 if (ifa->idev == idev) {
3410 hlist_del_init_rcu(&ifa->addr_lst);
3509 addrconf_del_dad_work(ifa); 3411 addrconf_del_dad_work(ifa);
3510 /* combined flag + permanent flag decide if 3412 goto restart;
3511 * address is retained on a down event
3512 */
3513 if (!keep_addr ||
3514 !(ifa->flags & IFA_F_PERMANENT) ||
3515 addr_is_local(&ifa->addr)) {
3516 hlist_del_init_rcu(&ifa->addr_lst);
3517 goto restart;
3518 }
3519 } 3413 }
3520 } 3414 }
3521 spin_unlock_bh(&addrconf_hash_lock); 3415 spin_unlock_bh(&addrconf_hash_lock);
@@ -3549,54 +3443,31 @@ restart:
3549 write_lock_bh(&idev->lock); 3443 write_lock_bh(&idev->lock);
3550 } 3444 }
3551 3445
3552 /* re-combine the user config with event to determine if permanent 3446 while (!list_empty(&idev->addr_list)) {
3553 * addresses are to be removed from the interface list 3447 ifa = list_first_entry(&idev->addr_list,
3554 */ 3448 struct inet6_ifaddr, if_list);
3555 keep_addr = (!how && _keep_addr > 0);
3556
3557 INIT_LIST_HEAD(&del_list);
3558 list_for_each_entry_safe(ifa, tmp, &idev->addr_list, if_list) {
3559 addrconf_del_dad_work(ifa); 3449 addrconf_del_dad_work(ifa);
3560 3450
3561 write_unlock_bh(&idev->lock); 3451 list_del(&ifa->if_list);
3562 spin_lock_bh(&ifa->lock);
3563
3564 if (keep_addr && (ifa->flags & IFA_F_PERMANENT) &&
3565 !addr_is_local(&ifa->addr)) {
3566 /* set state to skip the notifier below */
3567 state = INET6_IFADDR_STATE_DEAD;
3568 ifa->state = 0;
3569 if (!(ifa->flags & IFA_F_NODAD))
3570 ifa->flags |= IFA_F_TENTATIVE;
3571 } else {
3572 state = ifa->state;
3573 ifa->state = INET6_IFADDR_STATE_DEAD;
3574 3452
3575 list_del(&ifa->if_list); 3453 write_unlock_bh(&idev->lock);
3576 list_add(&ifa->if_list, &del_list);
3577 }
3578 3454
3455 spin_lock_bh(&ifa->lock);
3456 state = ifa->state;
3457 ifa->state = INET6_IFADDR_STATE_DEAD;
3579 spin_unlock_bh(&ifa->lock); 3458 spin_unlock_bh(&ifa->lock);
3580 3459
3581 if (state != INET6_IFADDR_STATE_DEAD) { 3460 if (state != INET6_IFADDR_STATE_DEAD) {
3582 __ipv6_ifa_notify(RTM_DELADDR, ifa); 3461 __ipv6_ifa_notify(RTM_DELADDR, ifa);
3583 inet6addr_notifier_call_chain(NETDEV_DOWN, ifa); 3462 inet6addr_notifier_call_chain(NETDEV_DOWN, ifa);
3584 } 3463 }
3464 in6_ifa_put(ifa);
3585 3465
3586 write_lock_bh(&idev->lock); 3466 write_lock_bh(&idev->lock);
3587 } 3467 }
3588 3468
3589 write_unlock_bh(&idev->lock); 3469 write_unlock_bh(&idev->lock);
3590 3470
3591 /* now clean up addresses to be removed */
3592 while (!list_empty(&del_list)) {
3593 ifa = list_first_entry(&del_list,
3594 struct inet6_ifaddr, if_list);
3595 list_del(&ifa->if_list);
3596
3597 in6_ifa_put(ifa);
3598 }
3599
3600 /* Step 5: Discard anycast and multicast list */ 3471 /* Step 5: Discard anycast and multicast list */
3601 if (how) { 3472 if (how) {
3602 ipv6_ac_destroy_dev(idev); 3473 ipv6_ac_destroy_dev(idev);
@@ -4861,7 +4732,6 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
4861 array[DEVCONF_USE_OIF_ADDRS_ONLY] = cnf->use_oif_addrs_only; 4732 array[DEVCONF_USE_OIF_ADDRS_ONLY] = cnf->use_oif_addrs_only;
4862 array[DEVCONF_DROP_UNICAST_IN_L2_MULTICAST] = cnf->drop_unicast_in_l2_multicast; 4733 array[DEVCONF_DROP_UNICAST_IN_L2_MULTICAST] = cnf->drop_unicast_in_l2_multicast;
4863 array[DEVCONF_DROP_UNSOLICITED_NA] = cnf->drop_unsolicited_na; 4734 array[DEVCONF_DROP_UNSOLICITED_NA] = cnf->drop_unsolicited_na;
4864 array[DEVCONF_KEEP_ADDR_ON_DOWN] = cnf->keep_addr_on_down;
4865} 4735}
4866 4736
4867static inline size_t inet6_ifla6_size(void) 4737static inline size_t inet6_ifla6_size(void)
@@ -5950,14 +5820,6 @@ static struct addrconf_sysctl_table
5950 .proc_handler = proc_dointvec, 5820 .proc_handler = proc_dointvec,
5951 }, 5821 },
5952 { 5822 {
5953 .procname = "keep_addr_on_down",
5954 .data = &ipv6_devconf.keep_addr_on_down,
5955 .maxlen = sizeof(int),
5956 .mode = 0644,
5957 .proc_handler = proc_dointvec,
5958
5959 },
5960 {
5961 /* sentinel */ 5823 /* sentinel */
5962 } 5824 }
5963 }, 5825 },