forked from Minki/linux
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
@ -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 @@ 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);
|
||||||
|
Loading…
Reference in New Issue
Block a user