Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1ec047eb authored by Hannes Frederic Sowa's avatar Hannes Frederic Sowa Committed by David S. Miller
Browse files

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: default avatarDavid Stevens <dlstevens@us.ibm.com>
Signed-off-by: default avatarHannes Frederic Sowa <hannes@stressinduktion.org>
Acked-by: default avatarFlavio Leitner <fbl@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ae0d6750
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -166,6 +166,7 @@ struct inet6_dev {
	struct net_device	*dev;
	struct net_device	*dev;


	struct list_head	addr_list;
	struct list_head	addr_list;
	int			valid_ll_addr_cnt;


	struct ifmcaddr6	*mc_list;
	struct ifmcaddr6	*mc_list;
	struct ifmcaddr6	*mc_tomb;
	struct ifmcaddr6	*mc_tomb;
+31 −8
Original line number Original line Diff line number Diff line
@@ -3277,6 +3277,7 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
{
{
	struct net_device *dev = ifp->idev->dev;
	struct net_device *dev = ifp->idev->dev;
	struct in6_addr lladdr;
	struct in6_addr lladdr;
	bool send_rs;


	addrconf_del_dad_timer(ifp);
	addrconf_del_dad_timer(ifp);


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


	if (ipv6_accept_ra(ifp->idev) &&
	read_lock_bh(&ifp->idev->lock);
	spin_lock(&ifp->lock);
	send_rs = ipv6_accept_ra(ifp->idev) &&
		  ifp->idev->cnf.rtr_solicits > 0 &&
		  ifp->idev->cnf.rtr_solicits > 0 &&
		  (dev->flags&IFF_LOOPBACK) == 0 &&
		  (dev->flags&IFF_LOOPBACK) == 0 &&
	    (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) {
		  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
		 *	If a host as already performed a random delay
		 *	[...] as part of DAD [...] there is no need
		 *	[...] as part of DAD [...] there is no need
		 *	to delay again before sending the first RS
		 *	to delay again before sending the first RS
		 */
		 */
		if (!ipv6_get_lladdr(dev, &lladdr, IFA_F_TENTATIVE))
		if (ipv6_get_lladdr(dev, &lladdr, IFA_F_TENTATIVE))
			ndisc_send_rs(dev, &lladdr,
				      &in6addr_linklocal_allrouters);
		else
			return;
			return;
		ndisc_send_rs(dev, &lladdr, &in6addr_linklocal_allrouters);


		write_lock_bh(&ifp->idev->lock);
		write_lock_bh(&ifp->idev->lock);
		spin_lock(&ifp->lock);
		spin_lock(&ifp->lock);
@@ -4576,6 +4582,19 @@ errout:
		rtnl_set_sk_err(net, RTNLGRP_IPV6_PREFIX, err);
		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)
static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
{
{
	struct net *net = dev_net(ifp->idev->dev);
	struct net *net = dev_net(ifp->idev->dev);
@@ -4584,6 +4603,8 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)


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

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

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