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 | |
| 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')
| -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); |
