mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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>
This commit is contained in:
		
							parent
							
								
									ae0d67505c
								
							
						
					
					
						commit
						1ec047eb47
					
				
					 2 changed files with 32 additions and 8 deletions
				
			
		| 
						 | 
					@ -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;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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);
 | 
				
			||||||
	    ifp->idev->cnf.rtr_solicits > 0 &&
 | 
						spin_lock(&ifp->lock);
 | 
				
			||||||
	    (dev->flags&IFF_LOOPBACK) == 0 &&
 | 
						send_rs = ipv6_accept_ra(ifp->idev) &&
 | 
				
			||||||
	    (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) {
 | 
							  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
 | 
							 *	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 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev,
 | 
				
			||||||
		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);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue