aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/addrconf.c
diff options
context:
space:
mode:
authorHannes Frederic Sowa <hannes@stressinduktion.org>2013-06-23 12:39:01 -0400
committerDavid S. Miller <davem@davemloft.net>2013-06-25 19:23:03 -0400
commitb7b1bfce0bb68bd8f6e62a28295922785cc63781 (patch)
tree212102b875b453496d86f8c448892bd90eb58c92 /net/ipv6/addrconf.c
parent51151a16a60f0a886a0b1e4a0697001198af50c4 (diff)
ipv6: split duplicate address detection and router solicitation timer
This patch splits the timers for duplicate address detection and router solicitations apart. The router solicitations timer goes into inet6_dev and the dad timer stays in inet6_ifaddr. The reason behind this patch is to reduce the number of unneeded router solicitations send out by the host if additional link-local addresses are created. Currently we send out RS for every link-local address on an interface. If the RS timer fires we pick a source address with ipv6_get_lladdr. This change could hurt people adding additional link-local addresses and specifying these addresses in the radvd clients section because we no longer guarantee that we use every ll address as source address in router solicitations. Cc: Flavio Leitner <fleitner@redhat.com> Cc: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org> Cc: David Stevens <dlstevens@us.ibm.com> Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Reviewed-by: Flavio Leitner <fbl@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r--net/ipv6/addrconf.c164
1 files changed, 91 insertions, 73 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 90788a1c6bbc..c06bc76280b2 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -253,37 +253,32 @@ static inline bool addrconf_qdisc_ok(const struct net_device *dev)
253 return !qdisc_tx_is_noop(dev); 253 return !qdisc_tx_is_noop(dev);
254} 254}
255 255
256static void addrconf_del_timer(struct inet6_ifaddr *ifp) 256static void addrconf_del_rs_timer(struct inet6_dev *idev)
257{ 257{
258 if (del_timer(&ifp->timer)) 258 if (del_timer(&idev->rs_timer))
259 __in6_dev_put(idev);
260}
261
262static void addrconf_del_dad_timer(struct inet6_ifaddr *ifp)
263{
264 if (del_timer(&ifp->dad_timer))
259 __in6_ifa_put(ifp); 265 __in6_ifa_put(ifp);
260} 266}
261 267
262enum addrconf_timer_t { 268static void addrconf_mod_rs_timer(struct inet6_dev *idev,
263 AC_NONE, 269 unsigned long when)
264 AC_DAD, 270{
265 AC_RS, 271 if (!timer_pending(&idev->rs_timer))
266}; 272 in6_dev_hold(idev);
273 mod_timer(&idev->rs_timer, jiffies + when);
274}
267 275
268static void addrconf_mod_timer(struct inet6_ifaddr *ifp, 276static void addrconf_mod_dad_timer(struct inet6_ifaddr *ifp,
269 enum addrconf_timer_t what, 277 unsigned long when)
270 unsigned long when)
271{ 278{
272 if (!del_timer(&ifp->timer)) 279 if (!timer_pending(&ifp->dad_timer))
273 in6_ifa_hold(ifp); 280 in6_ifa_hold(ifp);
274 281 mod_timer(&ifp->dad_timer, jiffies + when);
275 switch (what) {
276 case AC_DAD:
277 ifp->timer.function = addrconf_dad_timer;
278 break;
279 case AC_RS:
280 ifp->timer.function = addrconf_rs_timer;
281 break;
282 default:
283 break;
284 }
285 ifp->timer.expires = jiffies + when;
286 add_timer(&ifp->timer);
287} 282}
288 283
289static int snmp6_alloc_dev(struct inet6_dev *idev) 284static int snmp6_alloc_dev(struct inet6_dev *idev)
@@ -326,6 +321,7 @@ void in6_dev_finish_destroy(struct inet6_dev *idev)
326 321
327 WARN_ON(!list_empty(&idev->addr_list)); 322 WARN_ON(!list_empty(&idev->addr_list));
328 WARN_ON(idev->mc_list != NULL); 323 WARN_ON(idev->mc_list != NULL);
324 WARN_ON(timer_pending(&idev->rs_timer));
329 325
330#ifdef NET_REFCNT_DEBUG 326#ifdef NET_REFCNT_DEBUG
331 pr_debug("%s: %s\n", __func__, dev ? dev->name : "NIL"); 327 pr_debug("%s: %s\n", __func__, dev ? dev->name : "NIL");
@@ -357,7 +353,8 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
357 rwlock_init(&ndev->lock); 353 rwlock_init(&ndev->lock);
358 ndev->dev = dev; 354 ndev->dev = dev;
359 INIT_LIST_HEAD(&ndev->addr_list); 355 INIT_LIST_HEAD(&ndev->addr_list);
360 356 setup_timer(&ndev->rs_timer, addrconf_rs_timer,
357 (unsigned long)ndev);
361 memcpy(&ndev->cnf, dev_net(dev)->ipv6.devconf_dflt, sizeof(ndev->cnf)); 358 memcpy(&ndev->cnf, dev_net(dev)->ipv6.devconf_dflt, sizeof(ndev->cnf));
362 ndev->cnf.mtu6 = dev->mtu; 359 ndev->cnf.mtu6 = dev->mtu;
363 ndev->cnf.sysctl = NULL; 360 ndev->cnf.sysctl = NULL;
@@ -776,7 +773,7 @@ void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp)
776 773
777 in6_dev_put(ifp->idev); 774 in6_dev_put(ifp->idev);
778 775
779 if (del_timer(&ifp->timer)) 776 if (del_timer(&ifp->dad_timer))
780 pr_notice("Timer is still running, when freeing ifa=%p\n", ifp); 777 pr_notice("Timer is still running, when freeing ifa=%p\n", ifp);
781 778
782 if (ifp->state != INET6_IFADDR_STATE_DEAD) { 779 if (ifp->state != INET6_IFADDR_STATE_DEAD) {
@@ -869,9 +866,9 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
869 866
870 spin_lock_init(&ifa->lock); 867 spin_lock_init(&ifa->lock);
871 spin_lock_init(&ifa->state_lock); 868 spin_lock_init(&ifa->state_lock);
872 init_timer(&ifa->timer); 869 setup_timer(&ifa->dad_timer, addrconf_dad_timer,
870 (unsigned long)ifa);
873 INIT_HLIST_NODE(&ifa->addr_lst); 871 INIT_HLIST_NODE(&ifa->addr_lst);
874 ifa->timer.data = (unsigned long) ifa;
875 ifa->scope = scope; 872 ifa->scope = scope;
876 ifa->prefix_len = pfxlen; 873 ifa->prefix_len = pfxlen;
877 ifa->flags = flags | IFA_F_TENTATIVE; 874 ifa->flags = flags | IFA_F_TENTATIVE;
@@ -994,7 +991,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
994 } 991 }
995 write_unlock_bh(&idev->lock); 992 write_unlock_bh(&idev->lock);
996 993
997 addrconf_del_timer(ifp); 994 addrconf_del_dad_timer(ifp);
998 995
999 ipv6_ifa_notify(RTM_DELADDR, ifp); 996 ipv6_ifa_notify(RTM_DELADDR, ifp);
1000 997
@@ -1447,6 +1444,23 @@ try_nextdev:
1447} 1444}
1448EXPORT_SYMBOL(ipv6_dev_get_saddr); 1445EXPORT_SYMBOL(ipv6_dev_get_saddr);
1449 1446
1447static int __ipv6_get_lladdr(struct inet6_dev *idev, struct in6_addr *addr,
1448 unsigned char banned_flags)
1449{
1450 struct inet6_ifaddr *ifp;
1451 int err = -EADDRNOTAVAIL;
1452
1453 list_for_each_entry(ifp, &idev->addr_list, if_list) {
1454 if (ifp->scope == IFA_LINK &&
1455 !(ifp->flags & banned_flags)) {
1456 *addr = ifp->addr;
1457 err = 0;
1458 break;
1459 }
1460 }
1461 return err;
1462}
1463
1450int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr, 1464int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr,
1451 unsigned char banned_flags) 1465 unsigned char banned_flags)
1452{ 1466{
@@ -1456,17 +1470,8 @@ int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr,
1456 rcu_read_lock(); 1470 rcu_read_lock();
1457 idev = __in6_dev_get(dev); 1471 idev = __in6_dev_get(dev);
1458 if (idev) { 1472 if (idev) {
1459 struct inet6_ifaddr *ifp;
1460
1461 read_lock_bh(&idev->lock); 1473 read_lock_bh(&idev->lock);
1462 list_for_each_entry(ifp, &idev->addr_list, if_list) { 1474 err = __ipv6_get_lladdr(idev, addr, banned_flags);
1463 if (ifp->scope == IFA_LINK &&
1464 !(ifp->flags & banned_flags)) {
1465 *addr = ifp->addr;
1466 err = 0;
1467 break;
1468 }
1469 }
1470 read_unlock_bh(&idev->lock); 1475 read_unlock_bh(&idev->lock);
1471 } 1476 }
1472 rcu_read_unlock(); 1477 rcu_read_unlock();
@@ -1580,7 +1585,7 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp, int dad_failed)
1580{ 1585{
1581 if (ifp->flags&IFA_F_PERMANENT) { 1586 if (ifp->flags&IFA_F_PERMANENT) {
1582 spin_lock_bh(&ifp->lock); 1587 spin_lock_bh(&ifp->lock);
1583 addrconf_del_timer(ifp); 1588 addrconf_del_dad_timer(ifp);
1584 ifp->flags |= IFA_F_TENTATIVE; 1589 ifp->flags |= IFA_F_TENTATIVE;
1585 if (dad_failed) 1590 if (dad_failed)
1586 ifp->flags |= IFA_F_DADFAILED; 1591 ifp->flags |= IFA_F_DADFAILED;
@@ -3036,7 +3041,7 @@ static int addrconf_ifdown(struct net_device *dev, int how)
3036 hlist_for_each_entry_rcu(ifa, h, addr_lst) { 3041 hlist_for_each_entry_rcu(ifa, h, addr_lst) {
3037 if (ifa->idev == idev) { 3042 if (ifa->idev == idev) {
3038 hlist_del_init_rcu(&ifa->addr_lst); 3043 hlist_del_init_rcu(&ifa->addr_lst);
3039 addrconf_del_timer(ifa); 3044 addrconf_del_dad_timer(ifa);
3040 goto restart; 3045 goto restart;
3041 } 3046 }
3042 } 3047 }
@@ -3045,6 +3050,8 @@ static int addrconf_ifdown(struct net_device *dev, int how)
3045 3050
3046 write_lock_bh(&idev->lock); 3051 write_lock_bh(&idev->lock);
3047 3052
3053 addrconf_del_rs_timer(idev);
3054
3048 /* Step 2: clear flags for stateless addrconf */ 3055 /* Step 2: clear flags for stateless addrconf */
3049 if (!how) 3056 if (!how)
3050 idev->if_flags &= ~(IF_RS_SENT|IF_RA_RCVD|IF_READY); 3057 idev->if_flags &= ~(IF_RS_SENT|IF_RA_RCVD|IF_READY);
@@ -3074,7 +3081,7 @@ static int addrconf_ifdown(struct net_device *dev, int how)
3074 while (!list_empty(&idev->addr_list)) { 3081 while (!list_empty(&idev->addr_list)) {
3075 ifa = list_first_entry(&idev->addr_list, 3082 ifa = list_first_entry(&idev->addr_list,
3076 struct inet6_ifaddr, if_list); 3083 struct inet6_ifaddr, if_list);
3077 addrconf_del_timer(ifa); 3084 addrconf_del_dad_timer(ifa);
3078 3085
3079 list_del(&ifa->if_list); 3086 list_del(&ifa->if_list);
3080 3087
@@ -3116,10 +3123,10 @@ static int addrconf_ifdown(struct net_device *dev, int how)
3116 3123
3117static void addrconf_rs_timer(unsigned long data) 3124static void addrconf_rs_timer(unsigned long data)
3118{ 3125{
3119 struct inet6_ifaddr *ifp = (struct inet6_ifaddr *) data; 3126 struct inet6_dev *idev = (struct inet6_dev *)data;
3120 struct inet6_dev *idev = ifp->idev; 3127 struct in6_addr lladdr;
3121 3128
3122 read_lock(&idev->lock); 3129 write_lock(&idev->lock);
3123 if (idev->dead || !(idev->if_flags & IF_READY)) 3130 if (idev->dead || !(idev->if_flags & IF_READY))
3124 goto out; 3131 goto out;
3125 3132
@@ -3130,18 +3137,19 @@ static void addrconf_rs_timer(unsigned long data)
3130 if (idev->if_flags & IF_RA_RCVD) 3137 if (idev->if_flags & IF_RA_RCVD)
3131 goto out; 3138 goto out;
3132 3139
3133 spin_lock(&ifp->lock); 3140 if (idev->rs_probes++ < idev->cnf.rtr_solicits) {
3134 if (ifp->probes++ < idev->cnf.rtr_solicits) { 3141 if (!__ipv6_get_lladdr(idev, &lladdr, IFA_F_TENTATIVE))
3135 /* The wait after the last probe can be shorter */ 3142 ndisc_send_rs(idev->dev, &lladdr,
3136 addrconf_mod_timer(ifp, AC_RS, 3143 &in6addr_linklocal_allrouters);
3137 (ifp->probes == idev->cnf.rtr_solicits) ? 3144 else
3138 idev->cnf.rtr_solicit_delay : 3145 goto out;
3139 idev->cnf.rtr_solicit_interval);
3140 spin_unlock(&ifp->lock);
3141 3146
3142 ndisc_send_rs(idev->dev, &ifp->addr, &in6addr_linklocal_allrouters); 3147 /* The wait after the last probe can be shorter */
3148 addrconf_mod_rs_timer(idev, (idev->rs_probes ==
3149 idev->cnf.rtr_solicits) ?
3150 idev->cnf.rtr_solicit_delay :
3151 idev->cnf.rtr_solicit_interval);
3143 } else { 3152 } else {
3144 spin_unlock(&ifp->lock);
3145 /* 3153 /*
3146 * Note: we do not support deprecated "all on-link" 3154 * Note: we do not support deprecated "all on-link"
3147 * assumption any longer. 3155 * assumption any longer.
@@ -3150,8 +3158,8 @@ static void addrconf_rs_timer(unsigned long data)
3150 } 3158 }
3151 3159
3152out: 3160out:
3153 read_unlock(&idev->lock); 3161 write_unlock(&idev->lock);
3154 in6_ifa_put(ifp); 3162 in6_dev_put(idev);
3155} 3163}
3156 3164
3157/* 3165/*
@@ -3167,8 +3175,8 @@ static void addrconf_dad_kick(struct inet6_ifaddr *ifp)
3167 else 3175 else
3168 rand_num = net_random() % (idev->cnf.rtr_solicit_delay ? : 1); 3176 rand_num = net_random() % (idev->cnf.rtr_solicit_delay ? : 1);
3169 3177
3170 ifp->probes = idev->cnf.dad_transmits; 3178 ifp->dad_probes = idev->cnf.dad_transmits;
3171 addrconf_mod_timer(ifp, AC_DAD, rand_num); 3179 addrconf_mod_dad_timer(ifp, rand_num);
3172} 3180}
3173 3181
3174static void addrconf_dad_start(struct inet6_ifaddr *ifp) 3182static void addrconf_dad_start(struct inet6_ifaddr *ifp)
@@ -3229,40 +3237,40 @@ static void addrconf_dad_timer(unsigned long data)
3229 struct inet6_dev *idev = ifp->idev; 3237 struct inet6_dev *idev = ifp->idev;
3230 struct in6_addr mcaddr; 3238 struct in6_addr mcaddr;
3231 3239
3232 if (!ifp->probes && addrconf_dad_end(ifp)) 3240 if (!ifp->dad_probes && addrconf_dad_end(ifp))
3233 goto out; 3241 goto out;
3234 3242
3235 read_lock(&idev->lock); 3243 write_lock(&idev->lock);
3236 if (idev->dead || !(idev->if_flags & IF_READY)) { 3244 if (idev->dead || !(idev->if_flags & IF_READY)) {
3237 read_unlock(&idev->lock); 3245 write_unlock(&idev->lock);
3238 goto out; 3246 goto out;
3239 } 3247 }
3240 3248
3241 spin_lock(&ifp->lock); 3249 spin_lock(&ifp->lock);
3242 if (ifp->state == INET6_IFADDR_STATE_DEAD) { 3250 if (ifp->state == INET6_IFADDR_STATE_DEAD) {
3243 spin_unlock(&ifp->lock); 3251 spin_unlock(&ifp->lock);
3244 read_unlock(&idev->lock); 3252 write_unlock(&idev->lock);
3245 goto out; 3253 goto out;
3246 } 3254 }
3247 3255
3248 if (ifp->probes == 0) { 3256 if (ifp->dad_probes == 0) {
3249 /* 3257 /*
3250 * DAD was successful 3258 * DAD was successful
3251 */ 3259 */
3252 3260
3253 ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED); 3261 ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED);
3254 spin_unlock(&ifp->lock); 3262 spin_unlock(&ifp->lock);
3255 read_unlock(&idev->lock); 3263 write_unlock(&idev->lock);
3256 3264
3257 addrconf_dad_completed(ifp); 3265 addrconf_dad_completed(ifp);
3258 3266
3259 goto out; 3267 goto out;
3260 } 3268 }
3261 3269
3262 ifp->probes--; 3270 ifp->dad_probes--;
3263 addrconf_mod_timer(ifp, AC_DAD, ifp->idev->nd_parms->retrans_time); 3271 addrconf_mod_dad_timer(ifp, ifp->idev->nd_parms->retrans_time);
3264 spin_unlock(&ifp->lock); 3272 spin_unlock(&ifp->lock);
3265 read_unlock(&idev->lock); 3273 write_unlock(&idev->lock);
3266 3274
3267 /* send a neighbour solicitation for our addr */ 3275 /* send a neighbour solicitation for our addr */
3268 addrconf_addr_solict_mult(&ifp->addr, &mcaddr); 3276 addrconf_addr_solict_mult(&ifp->addr, &mcaddr);
@@ -3274,6 +3282,9 @@ out:
3274static void addrconf_dad_completed(struct inet6_ifaddr *ifp) 3282static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
3275{ 3283{
3276 struct net_device *dev = ifp->idev->dev; 3284 struct net_device *dev = ifp->idev->dev;
3285 struct in6_addr lladdr;
3286
3287 addrconf_del_dad_timer(ifp);
3277 3288
3278 /* 3289 /*
3279 * Configure the address for reception. Now it is valid. 3290 * Configure the address for reception. Now it is valid.
@@ -3294,13 +3305,20 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
3294 * [...] as part of DAD [...] there is no need 3305 * [...] as part of DAD [...] there is no need
3295 * to delay again before sending the first RS 3306 * to delay again before sending the first RS
3296 */ 3307 */
3297 ndisc_send_rs(ifp->idev->dev, &ifp->addr, &in6addr_linklocal_allrouters); 3308 if (!ipv6_get_lladdr(dev, &lladdr, IFA_F_TENTATIVE))
3309 ndisc_send_rs(dev, &lladdr,
3310 &in6addr_linklocal_allrouters);
3311 else
3312 return;
3298 3313
3299 spin_lock_bh(&ifp->lock); 3314 write_lock_bh(&ifp->idev->lock);
3300 ifp->probes = 1; 3315 spin_lock(&ifp->lock);
3316 ifp->idev->rs_probes = 1;
3301 ifp->idev->if_flags |= IF_RS_SENT; 3317 ifp->idev->if_flags |= IF_RS_SENT;
3302 addrconf_mod_timer(ifp, AC_RS, ifp->idev->cnf.rtr_solicit_interval); 3318 addrconf_mod_rs_timer(ifp->idev,
3303 spin_unlock_bh(&ifp->lock); 3319 ifp->idev->cnf.rtr_solicit_interval);
3320 spin_unlock(&ifp->lock);
3321 write_unlock_bh(&ifp->idev->lock);
3304 } 3322 }
3305} 3323}
3306 3324