Skip to content

Commit 11ffff7

Browse files
strssndktndavem330
authored andcommitted
ipv6: simplify detection of first operational link-local address on interface
In commit 1ec047e ("ipv6: introduce per-interface counter for dad-completed ipv6 addresses") I build the detection of the first operational link-local address much to complex. Additionally this code now has a race condition. Replace it with a much simpler variant, which just scans the address list when duplicate address detection completes, to check if this is the first valid link local address and send RS and MLD reports then. Fixes: 1ec047e ("ipv6: introduce per-interface counter for dad-completed ipv6 addresses") Reported-by: Jiri Pirko <[email protected]> Cc: Flavio Leitner <[email protected]> Signed-off-by: Hannes Frederic Sowa <[email protected]> Acked-by: Flavio Leitner <[email protected]> Acked-by: Jiri Pirko <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 77f99ad commit 11ffff7

File tree

2 files changed

+17
-22
lines changed

2 files changed

+17
-22
lines changed

include/net/if_inet6.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,6 @@ struct inet6_dev {
165165
struct net_device *dev;
166166

167167
struct list_head addr_list;
168-
int valid_ll_addr_cnt;
169168

170169
struct ifmcaddr6 *mc_list;
171170
struct ifmcaddr6 *mc_tomb;

net/ipv6/addrconf.c

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3189,6 +3189,22 @@ static void addrconf_dad_timer(unsigned long data)
31893189
in6_ifa_put(ifp);
31903190
}
31913191

3192+
/* ifp->idev must be at least read locked */
3193+
static bool ipv6_lonely_lladdr(struct inet6_ifaddr *ifp)
3194+
{
3195+
struct inet6_ifaddr *ifpiter;
3196+
struct inet6_dev *idev = ifp->idev;
3197+
3198+
list_for_each_entry(ifpiter, &idev->addr_list, if_list) {
3199+
if (ifp != ifpiter && ifpiter->scope == IFA_LINK &&
3200+
(ifpiter->flags & (IFA_F_PERMANENT|IFA_F_TENTATIVE|
3201+
IFA_F_OPTIMISTIC|IFA_F_DADFAILED)) ==
3202+
IFA_F_PERMANENT)
3203+
return false;
3204+
}
3205+
return true;
3206+
}
3207+
31923208
static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
31933209
{
31943210
struct net_device *dev = ifp->idev->dev;
@@ -3208,14 +3224,11 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
32083224
*/
32093225

32103226
read_lock_bh(&ifp->idev->lock);
3211-
spin_lock(&ifp->lock);
3212-
send_mld = ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL &&
3213-
ifp->idev->valid_ll_addr_cnt == 1;
3227+
send_mld = ifp->scope == IFA_LINK && ipv6_lonely_lladdr(ifp);
32143228
send_rs = send_mld &&
32153229
ipv6_accept_ra(ifp->idev) &&
32163230
ifp->idev->cnf.rtr_solicits > 0 &&
32173231
(dev->flags&IFF_LOOPBACK) == 0;
3218-
spin_unlock(&ifp->lock);
32193232
read_unlock_bh(&ifp->idev->lock);
32203233

32213234
/* While dad is in progress mld report's source address is in6_addrany.
@@ -4512,19 +4525,6 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev,
45124525
rtnl_set_sk_err(net, RTNLGRP_IPV6_PREFIX, err);
45134526
}
45144527

4515-
static void update_valid_ll_addr_cnt(struct inet6_ifaddr *ifp, int count)
4516-
{
4517-
write_lock_bh(&ifp->idev->lock);
4518-
spin_lock(&ifp->lock);
4519-
if (((ifp->flags & (IFA_F_PERMANENT|IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|
4520-
IFA_F_DADFAILED)) == IFA_F_PERMANENT) &&
4521-
(ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL))
4522-
ifp->idev->valid_ll_addr_cnt += count;
4523-
WARN_ON(ifp->idev->valid_ll_addr_cnt < 0);
4524-
spin_unlock(&ifp->lock);
4525-
write_unlock_bh(&ifp->idev->lock);
4526-
}
4527-
45284528
static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
45294529
{
45304530
struct net *net = dev_net(ifp->idev->dev);
@@ -4533,8 +4533,6 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
45334533

45344534
switch (event) {
45354535
case RTM_NEWADDR:
4536-
update_valid_ll_addr_cnt(ifp, 1);
4537-
45384536
/*
45394537
* If the address was optimistic
45404538
* we inserted the route at the start of
@@ -4550,8 +4548,6 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
45504548
ifp->idev->dev, 0, 0);
45514549
break;
45524550
case RTM_DELADDR:
4553-
update_valid_ll_addr_cnt(ifp, -1);
4554-
45554551
if (ifp->idev->cnf.forwarding)
45564552
addrconf_leave_anycast(ifp);
45574553
addrconf_leave_solict(ifp->idev, &ifp->addr);

0 commit comments

Comments
 (0)