aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHannes Frederic Sowa <hannes@stressinduktion.org>2013-06-26 18:06:56 -0400
committerDavid S. Miller <davem@davemloft.net>2013-06-29 00:19:17 -0400
commit1ec047eb4751e331bc61cff0e98f0db67db8b8dc (patch)
tree51f7272d5c26eb44e90624e682daa54c96064886
parentae0d67505ca30c635f7763564622c9710913f293 (diff)
ipv6: introduce per-interface counter for dad-completed ipv6 addresses
To reduce the number of unnecessary router solicitations, MLDv2 and IGMPv3 messages we need to track the number of valid (as in non-optimistic, no-dad-failed and non-tentative) link-local addresses. Therefore, this patch implements a valid_ll_addr_cnt in struct inet6_dev. We now only emit router solicitations if the first link-local address finishes duplicate address detection. The changes for MLDv2 and IGMPv3 are in a follow-up patch. While there, also simplify one if statement(one minor nit I made in one of my previous patches): if (!...) do(); else return; <<into>> if (...) return; do(); Cc: Flavio Leitner <fbl@redhat.com> Cc: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Cc: David Stevens <dlstevens@us.ibm.com> Suggested-by: David Stevens <dlstevens@us.ibm.com> Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Acked-by: Flavio Leitner <fbl@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/if_inet6.h1
-rw-r--r--net/ipv6/addrconf.c39
2 files changed, 32 insertions, 8 deletions
diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h
index e4c5a2d2ba34..1628b8f5fb26 100644
--- a/include/net/if_inet6.h
+++ b/include/net/if_inet6.h
@@ -166,6 +166,7 @@ struct inet6_dev {
166 struct net_device *dev; 166 struct net_device *dev;
167 167
168 struct list_head addr_list; 168 struct list_head addr_list;
169 int valid_ll_addr_cnt;
169 170
170 struct ifmcaddr6 *mc_list; 171 struct ifmcaddr6 *mc_list;
171 struct ifmcaddr6 *mc_tomb; 172 struct ifmcaddr6 *mc_tomb;
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 4e4cc1fc26d1..20d92ff2d690 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -3277,6 +3277,7 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
3277{ 3277{
3278 struct net_device *dev = ifp->idev->dev; 3278 struct net_device *dev = ifp->idev->dev;
3279 struct in6_addr lladdr; 3279 struct in6_addr lladdr;
3280 bool send_rs;
3280 3281
3281 addrconf_del_dad_timer(ifp); 3282 addrconf_del_dad_timer(ifp);
3282 3283
@@ -3290,20 +3291,25 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
3290 router advertisements, start sending router solicitations. 3291 router advertisements, start sending router solicitations.
3291 */ 3292 */
3292 3293
3293 if (ipv6_accept_ra(ifp->idev) && 3294 read_lock_bh(&ifp->idev->lock);
3294 ifp->idev->cnf.rtr_solicits > 0 && 3295 spin_lock(&ifp->lock);
3295 (dev->flags&IFF_LOOPBACK) == 0 && 3296 send_rs = ipv6_accept_ra(ifp->idev) &&
3296 (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) { 3297 ifp->idev->cnf.rtr_solicits > 0 &&
3298 (dev->flags&IFF_LOOPBACK) == 0 &&
3299 ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL &&
3300 ifp->idev->valid_ll_addr_cnt == 1;
3301 spin_unlock(&ifp->lock);
3302 read_unlock_bh(&ifp->idev->lock);
3303
3304 if (send_rs) {
3297 /* 3305 /*
3298 * If a host as already performed a random delay 3306 * If a host as already performed a random delay
3299 * [...] as part of DAD [...] there is no need 3307 * [...] as part of DAD [...] there is no need
3300 * to delay again before sending the first RS 3308 * to delay again before sending the first RS
3301 */ 3309 */
3302 if (!ipv6_get_lladdr(dev, &lladdr, IFA_F_TENTATIVE)) 3310 if (ipv6_get_lladdr(dev, &lladdr, IFA_F_TENTATIVE))
3303 ndisc_send_rs(dev, &lladdr,
3304 &in6addr_linklocal_allrouters);
3305 else
3306 return; 3311 return;
3312 ndisc_send_rs(dev, &lladdr, &in6addr_linklocal_allrouters);
3307 3313
3308 write_lock_bh(&ifp->idev->lock); 3314 write_lock_bh(&ifp->idev->lock);
3309 spin_lock(&ifp->lock); 3315 spin_lock(&ifp->lock);
@@ -4576,6 +4582,19 @@ errout:
4576 rtnl_set_sk_err(net, RTNLGRP_IPV6_PREFIX, err); 4582 rtnl_set_sk_err(net, RTNLGRP_IPV6_PREFIX, err);
4577} 4583}
4578 4584
4585static void update_valid_ll_addr_cnt(struct inet6_ifaddr *ifp, int count)
4586{
4587 write_lock_bh(&ifp->idev->lock);
4588 spin_lock(&ifp->lock);
4589 if (((ifp->flags & (IFA_F_PERMANENT|IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|
4590 IFA_F_DADFAILED)) == IFA_F_PERMANENT) &&
4591 (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL))
4592 ifp->idev->valid_ll_addr_cnt += count;
4593 WARN_ON(ifp->idev->valid_ll_addr_cnt < 0);
4594 spin_unlock(&ifp->lock);
4595 write_unlock_bh(&ifp->idev->lock);
4596}
4597
4579static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) 4598static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
4580{ 4599{
4581 struct net *net = dev_net(ifp->idev->dev); 4600 struct net *net = dev_net(ifp->idev->dev);
@@ -4584,6 +4603,8 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
4584 4603
4585 switch (event) { 4604 switch (event) {
4586 case RTM_NEWADDR: 4605 case RTM_NEWADDR:
4606 update_valid_ll_addr_cnt(ifp, 1);
4607
4587 /* 4608 /*
4588 * If the address was optimistic 4609 * If the address was optimistic
4589 * we inserted the route at the start of 4610 * we inserted the route at the start of
@@ -4599,6 +4620,8 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
4599 ifp->idev->dev, 0, 0); 4620 ifp->idev->dev, 0, 0);
4600 break; 4621 break;
4601 case RTM_DELADDR: 4622 case RTM_DELADDR:
4623 update_valid_ll_addr_cnt(ifp, -1);
4624
4602 if (ifp->idev->cnf.forwarding) 4625 if (ifp->idev->cnf.forwarding)
4603 addrconf_leave_anycast(ifp); 4626 addrconf_leave_anycast(ifp);
4604 addrconf_leave_solict(ifp->idev, &ifp->addr); 4627 addrconf_leave_solict(ifp->idev, &ifp->addr);