diff options
author | Hannes Frederic Sowa <hannes@stressinduktion.org> | 2013-06-26 18:06:56 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-06-29 00:19:17 -0400 |
commit | 1ec047eb4751e331bc61cff0e98f0db67db8b8dc (patch) | |
tree | 51f7272d5c26eb44e90624e682daa54c96064886 /net/ipv6/addrconf.c | |
parent | ae0d67505ca30c635f7763564622c9710913f293 (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>
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r-- | net/ipv6/addrconf.c | 39 |
1 files changed, 31 insertions, 8 deletions
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 | ||
4585 | static 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 | |||
4579 | static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) | 4598 | static 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); |