Commit 2aba913f authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

ipv6/addrconf: annotate data-races around devconf fields (I)

Annotate lockless reads and writes on following devconf fields:

- regen_min_advance
- regen_max_retry
- dad_transmits
- use_tempaddr
- max_addresses
- max_desync_factor
- temp_valid_lft
- rtr_solicits
- rtr_solicit_max_interval
- rtr_solicit_interval
- rtr_solicit_delay
- enhanced_dad
- accept_redirects
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Reviewed-by: default avatarJiri Pirko <jiri@nvidia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 45b90ec9
...@@ -1359,11 +1359,12 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) ...@@ -1359,11 +1359,12 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
in6_ifa_put(ifp); in6_ifa_put(ifp);
} }
static unsigned long ipv6_get_regen_advance(struct inet6_dev *idev) static unsigned long ipv6_get_regen_advance(const struct inet6_dev *idev)
{ {
return idev->cnf.regen_min_advance + idev->cnf.regen_max_retry * return READ_ONCE(idev->cnf.regen_min_advance) +
idev->cnf.dad_transmits * READ_ONCE(idev->cnf.regen_max_retry) *
max(NEIGH_VAR(idev->nd_parms, RETRANS_TIME), HZ/100) / HZ; READ_ONCE(idev->cnf.dad_transmits) *
max(NEIGH_VAR(idev->nd_parms, RETRANS_TIME), HZ/100) / HZ;
} }
static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block) static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block)
...@@ -1384,7 +1385,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block) ...@@ -1384,7 +1385,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block)
retry: retry:
in6_dev_hold(idev); in6_dev_hold(idev);
if (idev->cnf.use_tempaddr <= 0) { if (READ_ONCE(idev->cnf.use_tempaddr) <= 0) {
write_unlock_bh(&idev->lock); write_unlock_bh(&idev->lock);
pr_info("%s: use_tempaddr is disabled\n", __func__); pr_info("%s: use_tempaddr is disabled\n", __func__);
in6_dev_put(idev); in6_dev_put(idev);
...@@ -1392,8 +1393,8 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block) ...@@ -1392,8 +1393,8 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block)
goto out; goto out;
} }
spin_lock_bh(&ifp->lock); spin_lock_bh(&ifp->lock);
if (ifp->regen_count++ >= idev->cnf.regen_max_retry) { if (ifp->regen_count++ >= READ_ONCE(idev->cnf.regen_max_retry)) {
idev->cnf.use_tempaddr = -1; /*XXX*/ WRITE_ONCE(idev->cnf.use_tempaddr, -1); /*XXX*/
spin_unlock_bh(&ifp->lock); spin_unlock_bh(&ifp->lock);
write_unlock_bh(&idev->lock); write_unlock_bh(&idev->lock);
pr_warn("%s: regeneration time exceeded - disabled temporary address support\n", pr_warn("%s: regeneration time exceeded - disabled temporary address support\n",
...@@ -1415,7 +1416,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block) ...@@ -1415,7 +1416,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block)
*/ */
cnf_temp_preferred_lft = READ_ONCE(idev->cnf.temp_prefered_lft); cnf_temp_preferred_lft = READ_ONCE(idev->cnf.temp_prefered_lft);
max_desync_factor = min_t(long, max_desync_factor = min_t(long,
idev->cnf.max_desync_factor, READ_ONCE(idev->cnf.max_desync_factor),
cnf_temp_preferred_lft - regen_advance); cnf_temp_preferred_lft - regen_advance);
if (unlikely(idev->desync_factor > max_desync_factor)) { if (unlikely(idev->desync_factor > max_desync_factor)) {
...@@ -1432,7 +1433,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block) ...@@ -1432,7 +1433,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block)
memset(&cfg, 0, sizeof(cfg)); memset(&cfg, 0, sizeof(cfg));
cfg.valid_lft = min_t(__u32, ifp->valid_lft, cfg.valid_lft = min_t(__u32, ifp->valid_lft,
idev->cnf.temp_valid_lft + age); READ_ONCE(idev->cnf.temp_valid_lft) + age);
cfg.preferred_lft = cnf_temp_preferred_lft + age - idev->desync_factor; cfg.preferred_lft = cnf_temp_preferred_lft + age - idev->desync_factor;
cfg.preferred_lft = min_t(__u32, if_public_preferred_lft, cfg.preferred_lft); cfg.preferred_lft = min_t(__u32, if_public_preferred_lft, cfg.preferred_lft);
cfg.preferred_lft = min_t(__u32, cfg.valid_lft, cfg.preferred_lft); cfg.preferred_lft = min_t(__u32, cfg.valid_lft, cfg.preferred_lft);
...@@ -1685,7 +1686,7 @@ static int ipv6_get_saddr_eval(struct net *net, ...@@ -1685,7 +1686,7 @@ static int ipv6_get_saddr_eval(struct net *net,
*/ */
int preftmp = dst->prefs & (IPV6_PREFER_SRC_PUBLIC|IPV6_PREFER_SRC_TMP) ? int preftmp = dst->prefs & (IPV6_PREFER_SRC_PUBLIC|IPV6_PREFER_SRC_TMP) ?
!!(dst->prefs & IPV6_PREFER_SRC_TMP) : !!(dst->prefs & IPV6_PREFER_SRC_TMP) :
score->ifa->idev->cnf.use_tempaddr >= 2; READ_ONCE(score->ifa->idev->cnf.use_tempaddr) >= 2;
ret = (!(score->ifa->flags & IFA_F_TEMPORARY)) ^ preftmp; ret = (!(score->ifa->flags & IFA_F_TEMPORARY)) ^ preftmp;
break; break;
} }
...@@ -2168,6 +2169,7 @@ void addrconf_dad_failure(struct sk_buff *skb, struct inet6_ifaddr *ifp) ...@@ -2168,6 +2169,7 @@ void addrconf_dad_failure(struct sk_buff *skb, struct inet6_ifaddr *ifp)
{ {
struct inet6_dev *idev = ifp->idev; struct inet6_dev *idev = ifp->idev;
struct net *net = dev_net(idev->dev); struct net *net = dev_net(idev->dev);
int max_addresses;
if (addrconf_dad_end(ifp)) { if (addrconf_dad_end(ifp)) {
in6_ifa_put(ifp); in6_ifa_put(ifp);
...@@ -2205,9 +2207,9 @@ void addrconf_dad_failure(struct sk_buff *skb, struct inet6_ifaddr *ifp) ...@@ -2205,9 +2207,9 @@ void addrconf_dad_failure(struct sk_buff *skb, struct inet6_ifaddr *ifp)
spin_unlock_bh(&ifp->lock); spin_unlock_bh(&ifp->lock);
if (idev->cnf.max_addresses && max_addresses = READ_ONCE(idev->cnf.max_addresses);
ipv6_count_addresses(idev) >= if (max_addresses &&
idev->cnf.max_addresses) ipv6_count_addresses(idev) >= max_addresses)
goto lock_errdad; goto lock_errdad;
net_info_ratelimited("%s: generating new stable privacy address because of DAD conflict\n", net_info_ratelimited("%s: generating new stable privacy address because of DAD conflict\n",
...@@ -2604,11 +2606,11 @@ static void manage_tempaddrs(struct inet6_dev *idev, ...@@ -2604,11 +2606,11 @@ static void manage_tempaddrs(struct inet6_dev *idev,
* (TEMP_PREFERRED_LIFETIME - DESYNC_FACTOR), respectively. * (TEMP_PREFERRED_LIFETIME - DESYNC_FACTOR), respectively.
*/ */
age = (now - ift->cstamp) / HZ; age = (now - ift->cstamp) / HZ;
max_valid = idev->cnf.temp_valid_lft - age; max_valid = READ_ONCE(idev->cnf.temp_valid_lft) - age;
if (max_valid < 0) if (max_valid < 0)
max_valid = 0; max_valid = 0;
max_prefered = idev->cnf.temp_prefered_lft - max_prefered = READ_ONCE(idev->cnf.temp_prefered_lft) -
idev->desync_factor - age; idev->desync_factor - age;
if (max_prefered < 0) if (max_prefered < 0)
max_prefered = 0; max_prefered = 0;
...@@ -2641,7 +2643,7 @@ static void manage_tempaddrs(struct inet6_dev *idev, ...@@ -2641,7 +2643,7 @@ static void manage_tempaddrs(struct inet6_dev *idev,
if (list_empty(&idev->tempaddr_list) && (valid_lft || prefered_lft)) if (list_empty(&idev->tempaddr_list) && (valid_lft || prefered_lft))
create = true; create = true;
if (create && idev->cnf.use_tempaddr > 0) { if (create && READ_ONCE(idev->cnf.use_tempaddr) > 0) {
/* When a new public address is created as described /* When a new public address is created as described
* in [ADDRCONF], also create a new temporary address. * in [ADDRCONF], also create a new temporary address.
*/ */
...@@ -2669,7 +2671,7 @@ int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev, ...@@ -2669,7 +2671,7 @@ int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
int create = 0, update_lft = 0; int create = 0, update_lft = 0;
if (!ifp && valid_lft) { if (!ifp && valid_lft) {
int max_addresses = in6_dev->cnf.max_addresses; int max_addresses = READ_ONCE(in6_dev->cnf.max_addresses);
struct ifa6_config cfg = { struct ifa6_config cfg = {
.pfx = addr, .pfx = addr,
.plen = pinfo->prefix_len, .plen = pinfo->prefix_len,
...@@ -4028,6 +4030,7 @@ static void addrconf_rs_timer(struct timer_list *t) ...@@ -4028,6 +4030,7 @@ static void addrconf_rs_timer(struct timer_list *t)
struct inet6_dev *idev = from_timer(idev, t, rs_timer); struct inet6_dev *idev = from_timer(idev, t, rs_timer);
struct net_device *dev = idev->dev; struct net_device *dev = idev->dev;
struct in6_addr lladdr; struct in6_addr lladdr;
int rtr_solicits;
write_lock(&idev->lock); write_lock(&idev->lock);
if (idev->dead || !(idev->if_flags & IF_READY)) if (idev->dead || !(idev->if_flags & IF_READY))
...@@ -4040,7 +4043,9 @@ static void addrconf_rs_timer(struct timer_list *t) ...@@ -4040,7 +4043,9 @@ static void addrconf_rs_timer(struct timer_list *t)
if (idev->if_flags & IF_RA_RCVD) if (idev->if_flags & IF_RA_RCVD)
goto out; goto out;
if (idev->rs_probes++ < idev->cnf.rtr_solicits || idev->cnf.rtr_solicits < 0) { rtr_solicits = READ_ONCE(idev->cnf.rtr_solicits);
if (idev->rs_probes++ < rtr_solicits || rtr_solicits < 0) {
write_unlock(&idev->lock); write_unlock(&idev->lock);
if (!ipv6_get_lladdr(dev, &lladdr, IFA_F_TENTATIVE)) if (!ipv6_get_lladdr(dev, &lladdr, IFA_F_TENTATIVE))
ndisc_send_rs(dev, &lladdr, ndisc_send_rs(dev, &lladdr,
...@@ -4050,11 +4055,12 @@ static void addrconf_rs_timer(struct timer_list *t) ...@@ -4050,11 +4055,12 @@ static void addrconf_rs_timer(struct timer_list *t)
write_lock(&idev->lock); write_lock(&idev->lock);
idev->rs_interval = rfc3315_s14_backoff_update( idev->rs_interval = rfc3315_s14_backoff_update(
idev->rs_interval, idev->cnf.rtr_solicit_max_interval); idev->rs_interval,
READ_ONCE(idev->cnf.rtr_solicit_max_interval));
/* The wait after the last probe can be shorter */ /* The wait after the last probe can be shorter */
addrconf_mod_rs_timer(idev, (idev->rs_probes == addrconf_mod_rs_timer(idev, (idev->rs_probes ==
idev->cnf.rtr_solicits) ? READ_ONCE(idev->cnf.rtr_solicits)) ?
idev->cnf.rtr_solicit_delay : READ_ONCE(idev->cnf.rtr_solicit_delay) :
idev->rs_interval); idev->rs_interval);
} else { } else {
/* /*
...@@ -4075,24 +4081,25 @@ static void addrconf_rs_timer(struct timer_list *t) ...@@ -4075,24 +4081,25 @@ static void addrconf_rs_timer(struct timer_list *t)
*/ */
static void addrconf_dad_kick(struct inet6_ifaddr *ifp) static void addrconf_dad_kick(struct inet6_ifaddr *ifp)
{ {
unsigned long rand_num;
struct inet6_dev *idev = ifp->idev; struct inet6_dev *idev = ifp->idev;
unsigned long rand_num;
u64 nonce; u64 nonce;
if (ifp->flags & IFA_F_OPTIMISTIC) if (ifp->flags & IFA_F_OPTIMISTIC)
rand_num = 0; rand_num = 0;
else else
rand_num = get_random_u32_below(idev->cnf.rtr_solicit_delay ? : 1); rand_num = get_random_u32_below(
READ_ONCE(idev->cnf.rtr_solicit_delay) ? : 1);
nonce = 0; nonce = 0;
if (idev->cnf.enhanced_dad || if (READ_ONCE(idev->cnf.enhanced_dad) ||
dev_net(idev->dev)->ipv6.devconf_all->enhanced_dad) { READ_ONCE(dev_net(idev->dev)->ipv6.devconf_all->enhanced_dad)) {
do do
get_random_bytes(&nonce, 6); get_random_bytes(&nonce, 6);
while (nonce == 0); while (nonce == 0);
} }
ifp->dad_nonce = nonce; ifp->dad_nonce = nonce;
ifp->dad_probes = idev->cnf.dad_transmits; ifp->dad_probes = READ_ONCE(idev->cnf.dad_transmits);
addrconf_mod_dad_work(ifp, rand_num); addrconf_mod_dad_work(ifp, rand_num);
} }
...@@ -4331,7 +4338,7 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp, bool bump_id, ...@@ -4331,7 +4338,7 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp, bool bump_id,
send_mld = ifp->scope == IFA_LINK && ipv6_lonely_lladdr(ifp); send_mld = ifp->scope == IFA_LINK && ipv6_lonely_lladdr(ifp);
send_rs = send_mld && send_rs = send_mld &&
ipv6_accept_ra(ifp->idev) && ipv6_accept_ra(ifp->idev) &&
ifp->idev->cnf.rtr_solicits != 0 && READ_ONCE(ifp->idev->cnf.rtr_solicits) != 0 &&
(dev->flags & IFF_LOOPBACK) == 0 && (dev->flags & IFF_LOOPBACK) == 0 &&
(dev->type != ARPHRD_TUNNEL) && (dev->type != ARPHRD_TUNNEL) &&
!netif_is_team_port(dev); !netif_is_team_port(dev);
...@@ -4366,7 +4373,7 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp, bool bump_id, ...@@ -4366,7 +4373,7 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp, bool bump_id,
write_lock_bh(&ifp->idev->lock); write_lock_bh(&ifp->idev->lock);
spin_lock(&ifp->lock); spin_lock(&ifp->lock);
ifp->idev->rs_interval = rfc3315_s14_backoff_init( ifp->idev->rs_interval = rfc3315_s14_backoff_init(
ifp->idev->cnf.rtr_solicit_interval); READ_ONCE(ifp->idev->cnf.rtr_solicit_interval));
ifp->idev->rs_probes = 1; ifp->idev->rs_probes = 1;
ifp->idev->if_flags |= IF_RS_SENT; ifp->idev->if_flags |= IF_RS_SENT;
addrconf_mod_rs_timer(ifp->idev, ifp->idev->rs_interval); addrconf_mod_rs_timer(ifp->idev, ifp->idev->rs_interval);
...@@ -5915,7 +5922,7 @@ static int inet6_set_iftoken(struct inet6_dev *idev, struct in6_addr *token, ...@@ -5915,7 +5922,7 @@ static int inet6_set_iftoken(struct inet6_dev *idev, struct in6_addr *token,
return -EINVAL; return -EINVAL;
} }
if (idev->cnf.rtr_solicits == 0) { if (READ_ONCE(idev->cnf.rtr_solicits) == 0) {
NL_SET_ERR_MSG(extack, NL_SET_ERR_MSG(extack,
"Router solicitation is disabled on device"); "Router solicitation is disabled on device");
return -EINVAL; return -EINVAL;
...@@ -5948,7 +5955,7 @@ static int inet6_set_iftoken(struct inet6_dev *idev, struct in6_addr *token, ...@@ -5948,7 +5955,7 @@ static int inet6_set_iftoken(struct inet6_dev *idev, struct in6_addr *token,
if (update_rs) { if (update_rs) {
idev->if_flags |= IF_RS_SENT; idev->if_flags |= IF_RS_SENT;
idev->rs_interval = rfc3315_s14_backoff_init( idev->rs_interval = rfc3315_s14_backoff_init(
idev->cnf.rtr_solicit_interval); READ_ONCE(idev->cnf.rtr_solicit_interval));
idev->rs_probes = 1; idev->rs_probes = 1;
addrconf_mod_rs_timer(idev, idev->rs_interval); addrconf_mod_rs_timer(idev, idev->rs_interval);
} }
......
...@@ -4150,7 +4150,8 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu ...@@ -4150,7 +4150,8 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
in6_dev = __in6_dev_get(skb->dev); in6_dev = __in6_dev_get(skb->dev);
if (!in6_dev) if (!in6_dev)
return; return;
if (READ_ONCE(in6_dev->cnf.forwarding) || !in6_dev->cnf.accept_redirects) if (READ_ONCE(in6_dev->cnf.forwarding) ||
!READ_ONCE(in6_dev->cnf.accept_redirects))
return; return;
/* RFC2461 8.1: /* RFC2461 8.1:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment