Skip to content

Commit

Permalink
ipv6: introduce per-interface counter for dad-completed ipv6 addresses
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Hannes Frederic Sowa authored and David S. Miller committed Jun 29, 2013
1 parent ae0d675 commit 1ec047e
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 8 deletions.
1 change: 1 addition & 0 deletions include/net/if_inet6.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ struct inet6_dev {
struct net_device *dev;

struct list_head addr_list;
int valid_ll_addr_cnt;

struct ifmcaddr6 *mc_list;
struct ifmcaddr6 *mc_tomb;
Expand Down
39 changes: 31 additions & 8 deletions net/ipv6/addrconf.c
Original file line number Diff line number Diff line change
Expand Up @@ -3277,6 +3277,7 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
{
struct net_device *dev = ifp->idev->dev;
struct in6_addr lladdr;
bool send_rs;

addrconf_del_dad_timer(ifp);

Expand All @@ -3290,20 +3291,25 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
router advertisements, start sending router solicitations.
*/

if (ipv6_accept_ra(ifp->idev) &&
ifp->idev->cnf.rtr_solicits > 0 &&
(dev->flags&IFF_LOOPBACK) == 0 &&
(ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) {
read_lock_bh(&ifp->idev->lock);
spin_lock(&ifp->lock);
send_rs = ipv6_accept_ra(ifp->idev) &&
ifp->idev->cnf.rtr_solicits > 0 &&
(dev->flags&IFF_LOOPBACK) == 0 &&
ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL &&
ifp->idev->valid_ll_addr_cnt == 1;
spin_unlock(&ifp->lock);
read_unlock_bh(&ifp->idev->lock);

if (send_rs) {
/*
* If a host as already performed a random delay
* [...] as part of DAD [...] there is no need
* to delay again before sending the first RS
*/
if (!ipv6_get_lladdr(dev, &lladdr, IFA_F_TENTATIVE))
ndisc_send_rs(dev, &lladdr,
&in6addr_linklocal_allrouters);
else
if (ipv6_get_lladdr(dev, &lladdr, IFA_F_TENTATIVE))
return;
ndisc_send_rs(dev, &lladdr, &in6addr_linklocal_allrouters);

write_lock_bh(&ifp->idev->lock);
spin_lock(&ifp->lock);
Expand Down Expand Up @@ -4576,6 +4582,19 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev,
rtnl_set_sk_err(net, RTNLGRP_IPV6_PREFIX, err);
}

static void update_valid_ll_addr_cnt(struct inet6_ifaddr *ifp, int count)
{
write_lock_bh(&ifp->idev->lock);
spin_lock(&ifp->lock);
if (((ifp->flags & (IFA_F_PERMANENT|IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|
IFA_F_DADFAILED)) == IFA_F_PERMANENT) &&
(ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL))
ifp->idev->valid_ll_addr_cnt += count;
WARN_ON(ifp->idev->valid_ll_addr_cnt < 0);
spin_unlock(&ifp->lock);
write_unlock_bh(&ifp->idev->lock);
}

static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
{
struct net *net = dev_net(ifp->idev->dev);
Expand All @@ -4584,6 +4603,8 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)

switch (event) {
case RTM_NEWADDR:
update_valid_ll_addr_cnt(ifp, 1);

/*
* If the address was optimistic
* we inserted the route at the start of
Expand All @@ -4599,6 +4620,8 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
ifp->idev->dev, 0, 0);
break;
case RTM_DELADDR:
update_valid_ll_addr_cnt(ifp, -1);

if (ifp->idev->cnf.forwarding)
addrconf_leave_anycast(ifp);
addrconf_leave_solict(ifp->idev, &ifp->addr);
Expand Down

0 comments on commit 1ec047e

Please sign in to comment.