Skip to content

Commit 2f0ff05

Browse files
edumazetdavem330
authored andcommitted
ipv6/addrconf: annotate data-races around devconf fields (II)
Final (?) round of this series. Annotate lockless reads on following devconf fields, because they be changed concurrently from /proc/net/ipv6/conf. - accept_dad - optimistic_dad - use_optimistic - use_oif_addrs_only - ra_honor_pio_life - keep_addr_on_down - ndisc_notify - ndisc_evict_nocarrier - suppress_frag_ndisc - addr_gen_mode - seg6_enabled - ioam6_enabled - ioam6_id - ioam6_id_wide - drop_unicast_in_l2_multicast - mldv[12]_unsolicited_report_interval - force_mld_version - force_tllao - accept_untracked_na - drop_unsolicited_na - accept_source_route Signed-off-by: Eric Dumazet <[email protected]> Reviewed-by: Jiri Pirko <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 2aba913 commit 2f0ff05

File tree

7 files changed

+61
-54
lines changed

7 files changed

+61
-54
lines changed

net/ipv6/addrconf.c

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1557,15 +1557,17 @@ static inline int ipv6_saddr_preferred(int type)
15571557
return 0;
15581558
}
15591559

1560-
static bool ipv6_use_optimistic_addr(struct net *net,
1561-
struct inet6_dev *idev)
1560+
static bool ipv6_use_optimistic_addr(const struct net *net,
1561+
const struct inet6_dev *idev)
15621562
{
15631563
#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
15641564
if (!idev)
15651565
return false;
1566-
if (!net->ipv6.devconf_all->optimistic_dad && !idev->cnf.optimistic_dad)
1566+
if (!READ_ONCE(net->ipv6.devconf_all->optimistic_dad) &&
1567+
!READ_ONCE(idev->cnf.optimistic_dad))
15671568
return false;
1568-
if (!net->ipv6.devconf_all->use_optimistic && !idev->cnf.use_optimistic)
1569+
if (!READ_ONCE(net->ipv6.devconf_all->use_optimistic) &&
1570+
!READ_ONCE(idev->cnf.use_optimistic))
15691571
return false;
15701572

15711573
return true;
@@ -1574,13 +1576,14 @@ static bool ipv6_use_optimistic_addr(struct net *net,
15741576
#endif
15751577
}
15761578

1577-
static bool ipv6_allow_optimistic_dad(struct net *net,
1578-
struct inet6_dev *idev)
1579+
static bool ipv6_allow_optimistic_dad(const struct net *net,
1580+
const struct inet6_dev *idev)
15791581
{
15801582
#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
15811583
if (!idev)
15821584
return false;
1583-
if (!net->ipv6.devconf_all->optimistic_dad && !idev->cnf.optimistic_dad)
1585+
if (!READ_ONCE(net->ipv6.devconf_all->optimistic_dad) &&
1586+
!READ_ONCE(idev->cnf.optimistic_dad))
15841587
return false;
15851588

15861589
return true;
@@ -1862,7 +1865,7 @@ int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev,
18621865
idev = __in6_dev_get(dst_dev);
18631866
if ((dst_type & IPV6_ADDR_MULTICAST) ||
18641867
dst.scope <= IPV6_ADDR_SCOPE_LINKLOCAL ||
1865-
(idev && idev->cnf.use_oif_addrs_only)) {
1868+
(idev && READ_ONCE(idev->cnf.use_oif_addrs_only))) {
18661869
use_oif_addr = true;
18671870
}
18681871
}
@@ -2683,8 +2686,8 @@ int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
26832686
};
26842687

26852688
#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
2686-
if ((net->ipv6.devconf_all->optimistic_dad ||
2687-
in6_dev->cnf.optimistic_dad) &&
2689+
if ((READ_ONCE(net->ipv6.devconf_all->optimistic_dad) ||
2690+
READ_ONCE(in6_dev->cnf.optimistic_dad)) &&
26882691
!net->ipv6.devconf_all->forwarding && sllao)
26892692
cfg.ifa_flags |= IFA_F_OPTIMISTIC;
26902693
#endif
@@ -2733,7 +2736,7 @@ int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
27332736
*/
27342737
update_lft = !create && stored_lft;
27352738

2736-
if (update_lft && !in6_dev->cnf.ra_honor_pio_life) {
2739+
if (update_lft && !READ_ONCE(in6_dev->cnf.ra_honor_pio_life)) {
27372740
const u32 minimum_lft = min_t(u32,
27382741
stored_lft, MIN_VALID_LIFETIME);
27392742
valid_lft = max(valid_lft, minimum_lft);
@@ -3317,8 +3320,8 @@ void addrconf_add_linklocal(struct inet6_dev *idev,
33173320
struct inet6_ifaddr *ifp;
33183321

33193322
#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
3320-
if ((dev_net(idev->dev)->ipv6.devconf_all->optimistic_dad ||
3321-
idev->cnf.optimistic_dad) &&
3323+
if ((READ_ONCE(dev_net(idev->dev)->ipv6.devconf_all->optimistic_dad) ||
3324+
READ_ONCE(idev->cnf.optimistic_dad)) &&
33223325
!dev_net(idev->dev)->ipv6.devconf_all->forwarding)
33233326
cfg.ifa_flags |= IFA_F_OPTIMISTIC;
33243327
#endif
@@ -3890,10 +3893,10 @@ static int addrconf_ifdown(struct net_device *dev, bool unregister)
38903893
*/
38913894
if (!unregister && !idev->cnf.disable_ipv6) {
38923895
/* aggregate the system setting and interface setting */
3893-
int _keep_addr = net->ipv6.devconf_all->keep_addr_on_down;
3896+
int _keep_addr = READ_ONCE(net->ipv6.devconf_all->keep_addr_on_down);
38943897

38953898
if (!_keep_addr)
3896-
_keep_addr = idev->cnf.keep_addr_on_down;
3899+
_keep_addr = READ_ONCE(idev->cnf.keep_addr_on_down);
38973900

38983901
keep_addr = (_keep_addr > 0);
38993902
}
@@ -4119,8 +4122,8 @@ static void addrconf_dad_begin(struct inet6_ifaddr *ifp)
41194122

41204123
net = dev_net(dev);
41214124
if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) ||
4122-
(net->ipv6.devconf_all->accept_dad < 1 &&
4123-
idev->cnf.accept_dad < 1) ||
4125+
(READ_ONCE(net->ipv6.devconf_all->accept_dad) < 1 &&
4126+
READ_ONCE(idev->cnf.accept_dad) < 1) ||
41244127
!(ifp->flags&IFA_F_TENTATIVE) ||
41254128
ifp->flags & IFA_F_NODAD) {
41264129
bool send_na = false;
@@ -4212,8 +4215,8 @@ static void addrconf_dad_work(struct work_struct *w)
42124215
action = DAD_ABORT;
42134216
ifp->state = INET6_IFADDR_STATE_POSTDAD;
42144217

4215-
if ((dev_net(idev->dev)->ipv6.devconf_all->accept_dad > 1 ||
4216-
idev->cnf.accept_dad > 1) &&
4218+
if ((READ_ONCE(dev_net(idev->dev)->ipv6.devconf_all->accept_dad) > 1 ||
4219+
READ_ONCE(idev->cnf.accept_dad) > 1) &&
42174220
!idev->cnf.disable_ipv6 &&
42184221
!(ifp->flags & IFA_F_STABLE_PRIVACY)) {
42194222
struct in6_addr addr;
@@ -4352,8 +4355,8 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp, bool bump_id,
43524355

43534356
/* send unsolicited NA if enabled */
43544357
if (send_na &&
4355-
(ifp->idev->cnf.ndisc_notify ||
4356-
dev_net(dev)->ipv6.devconf_all->ndisc_notify)) {
4358+
(READ_ONCE(ifp->idev->cnf.ndisc_notify) ||
4359+
READ_ONCE(dev_net(dev)->ipv6.devconf_all->ndisc_notify))) {
43574360
ndisc_send_na(dev, &in6addr_linklocal_allnodes, &ifp->addr,
43584361
/*router=*/ !!ifp->idev->cnf.forwarding,
43594362
/*solicited=*/ false, /*override=*/ true,
@@ -6541,7 +6544,7 @@ static int addrconf_sysctl_addr_gen_mode(struct ctl_table *ctl, int write,
65416544
} else if (&net->ipv6.devconf_all->addr_gen_mode == ctl->data) {
65426545
struct net_device *dev;
65436546

6544-
net->ipv6.devconf_dflt->addr_gen_mode = new_val;
6547+
WRITE_ONCE(net->ipv6.devconf_dflt->addr_gen_mode, new_val);
65456548
for_each_netdev(net, dev) {
65466549
idev = __in6_dev_get(dev);
65476550
if (idev &&
@@ -6553,7 +6556,7 @@ static int addrconf_sysctl_addr_gen_mode(struct ctl_table *ctl, int write,
65536556
}
65546557
}
65556558

6556-
*((u32 *)ctl->data) = new_val;
6559+
WRITE_ONCE(*((u32 *)ctl->data), new_val);
65576560
}
65586561

65596562
out:

net/ipv6/exthdrs.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -379,9 +379,8 @@ static int ipv6_srh_rcv(struct sk_buff *skb)
379379

380380
idev = __in6_dev_get(skb->dev);
381381

382-
accept_seg6 = net->ipv6.devconf_all->seg6_enabled;
383-
if (accept_seg6 > idev->cnf.seg6_enabled)
384-
accept_seg6 = idev->cnf.seg6_enabled;
382+
accept_seg6 = min(READ_ONCE(net->ipv6.devconf_all->seg6_enabled),
383+
READ_ONCE(idev->cnf.seg6_enabled));
385384

386385
if (!accept_seg6) {
387386
kfree_skb(skb);
@@ -655,10 +654,13 @@ static int ipv6_rthdr_rcv(struct sk_buff *skb)
655654
struct ipv6_rt_hdr *hdr;
656655
struct rt0_hdr *rthdr;
657656
struct net *net = dev_net(skb->dev);
658-
int accept_source_route = net->ipv6.devconf_all->accept_source_route;
657+
int accept_source_route;
659658

660-
if (idev && accept_source_route > idev->cnf.accept_source_route)
661-
accept_source_route = idev->cnf.accept_source_route;
659+
accept_source_route = READ_ONCE(net->ipv6.devconf_all->accept_source_route);
660+
661+
if (idev)
662+
accept_source_route = min(accept_source_route,
663+
READ_ONCE(idev->cnf.accept_source_route));
662664

663665
if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
664666
!pskb_may_pull(skb, (skb_transport_offset(skb) +
@@ -919,7 +921,7 @@ static bool ipv6_hop_ioam(struct sk_buff *skb, int optoff)
919921
goto drop;
920922

921923
/* Ignore if IOAM is not enabled on ingress */
922-
if (!__in6_dev_get(skb->dev)->cnf.ioam6_enabled)
924+
if (!READ_ONCE(__in6_dev_get(skb->dev)->cnf.ioam6_enabled))
923925
goto ignore;
924926

925927
/* Truncated Option header */

net/ipv6/ioam6.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -727,15 +727,15 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
727727
if (!skb->dev)
728728
raw16 = IOAM6_U16_UNAVAILABLE;
729729
else
730-
raw16 = (__force u16)__in6_dev_get(skb->dev)->cnf.ioam6_id;
730+
raw16 = (__force u16)READ_ONCE(__in6_dev_get(skb->dev)->cnf.ioam6_id);
731731

732732
*(__be16 *)data = cpu_to_be16(raw16);
733733
data += sizeof(__be16);
734734

735735
if (skb_dst(skb)->dev->flags & IFF_LOOPBACK)
736736
raw16 = IOAM6_U16_UNAVAILABLE;
737737
else
738-
raw16 = (__force u16)__in6_dev_get(skb_dst(skb)->dev)->cnf.ioam6_id;
738+
raw16 = (__force u16)READ_ONCE(__in6_dev_get(skb_dst(skb)->dev)->cnf.ioam6_id);
739739

740740
*(__be16 *)data = cpu_to_be16(raw16);
741741
data += sizeof(__be16);
@@ -822,15 +822,15 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
822822
if (!skb->dev)
823823
raw32 = IOAM6_U32_UNAVAILABLE;
824824
else
825-
raw32 = __in6_dev_get(skb->dev)->cnf.ioam6_id_wide;
825+
raw32 = READ_ONCE(__in6_dev_get(skb->dev)->cnf.ioam6_id_wide);
826826

827827
*(__be32 *)data = cpu_to_be32(raw32);
828828
data += sizeof(__be32);
829829

830830
if (skb_dst(skb)->dev->flags & IFF_LOOPBACK)
831831
raw32 = IOAM6_U32_UNAVAILABLE;
832832
else
833-
raw32 = __in6_dev_get(skb_dst(skb)->dev)->cnf.ioam6_id_wide;
833+
raw32 = READ_ONCE(__in6_dev_get(skb_dst(skb)->dev)->cnf.ioam6_id_wide);
834834

835835
*(__be32 *)data = cpu_to_be32(raw32);
836836
data += sizeof(__be32);

net/ipv6/ip6_input.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev,
236236
if (!ipv6_addr_is_multicast(&hdr->daddr) &&
237237
(skb->pkt_type == PACKET_BROADCAST ||
238238
skb->pkt_type == PACKET_MULTICAST) &&
239-
idev->cnf.drop_unicast_in_l2_multicast) {
239+
READ_ONCE(idev->cnf.drop_unicast_in_l2_multicast)) {
240240
SKB_DR_SET(reason, UNICAST_IN_L2_MULTICAST);
241241
goto err;
242242
}

net/ipv6/mcast.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -159,9 +159,9 @@ static int unsolicited_report_interval(struct inet6_dev *idev)
159159
int iv;
160160

161161
if (mld_in_v1_mode(idev))
162-
iv = idev->cnf.mldv1_unsolicited_report_interval;
162+
iv = READ_ONCE(idev->cnf.mldv1_unsolicited_report_interval);
163163
else
164-
iv = idev->cnf.mldv2_unsolicited_report_interval;
164+
iv = READ_ONCE(idev->cnf.mldv2_unsolicited_report_interval);
165165

166166
return iv > 0 ? iv : 1;
167167
}
@@ -1202,15 +1202,15 @@ static bool mld_marksources(struct ifmcaddr6 *pmc, int nsrcs,
12021202

12031203
static int mld_force_mld_version(const struct inet6_dev *idev)
12041204
{
1205+
const struct net *net = dev_net(idev->dev);
1206+
int all_force;
1207+
1208+
all_force = READ_ONCE(net->ipv6.devconf_all->force_mld_version);
12051209
/* Normally, both are 0 here. If enforcement to a particular is
12061210
* being used, individual device enforcement will have a lower
12071211
* precedence over 'all' device (.../conf/all/force_mld_version).
12081212
*/
1209-
1210-
if (dev_net(idev->dev)->ipv6.devconf_all->force_mld_version != 0)
1211-
return dev_net(idev->dev)->ipv6.devconf_all->force_mld_version;
1212-
else
1213-
return idev->cnf.force_mld_version;
1213+
return all_force ?: READ_ONCE(idev->cnf.force_mld_version);
12141214
}
12151215

12161216
static bool mld_in_v2_mode_only(const struct inet6_dev *idev)

net/ipv6/ndisc.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ static void ip6_nd_hdr(struct sk_buff *skb,
451451

452452
rcu_read_lock();
453453
idev = __in6_dev_get(skb->dev);
454-
tclass = idev ? idev->cnf.ndisc_tclass : 0;
454+
tclass = idev ? READ_ONCE(idev->cnf.ndisc_tclass) : 0;
455455
rcu_read_unlock();
456456

457457
skb_push(skb, sizeof(*hdr));
@@ -535,7 +535,7 @@ void ndisc_send_na(struct net_device *dev, const struct in6_addr *daddr,
535535
src_addr = solicited_addr;
536536
if (ifp->flags & IFA_F_OPTIMISTIC)
537537
override = false;
538-
inc_opt |= ifp->idev->cnf.force_tllao;
538+
inc_opt |= READ_ONCE(ifp->idev->cnf.force_tllao);
539539
in6_ifa_put(ifp);
540540
} else {
541541
if (ipv6_dev_get_saddr(dev_net(dev), dev, daddr,
@@ -974,7 +974,7 @@ static int accept_untracked_na(struct net_device *dev, struct in6_addr *saddr)
974974
{
975975
struct inet6_dev *idev = __in6_dev_get(dev);
976976

977-
switch (idev->cnf.accept_untracked_na) {
977+
switch (READ_ONCE(idev->cnf.accept_untracked_na)) {
978978
case 0: /* Don't accept untracked na (absent in neighbor cache) */
979979
return 0;
980980
case 1: /* Create new entries from na if currently untracked */
@@ -1025,7 +1025,7 @@ static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb)
10251025
* drop_unsolicited_na takes precedence over accept_untracked_na
10261026
*/
10271027
if (!msg->icmph.icmp6_solicited && idev &&
1028-
idev->cnf.drop_unsolicited_na)
1028+
READ_ONCE(idev->cnf.drop_unsolicited_na))
10291029
return reason;
10301030

10311031
if (!ndisc_parse_options(dev, msg->opt, ndoptlen, &ndopts))
@@ -1818,7 +1818,7 @@ static bool ndisc_suppress_frag_ndisc(struct sk_buff *skb)
18181818
if (!idev)
18191819
return true;
18201820
if (IP6CB(skb)->flags & IP6SKB_FRAGMENTED &&
1821-
idev->cnf.suppress_frag_ndisc) {
1821+
READ_ONCE(idev->cnf.suppress_frag_ndisc)) {
18221822
net_warn_ratelimited("Received fragmented ndisc packet. Carefully consider disabling suppress_frag_ndisc.\n");
18231823
return true;
18241824
}
@@ -1895,8 +1895,8 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event,
18951895
idev = in6_dev_get(dev);
18961896
if (!idev)
18971897
break;
1898-
if (idev->cnf.ndisc_notify ||
1899-
net->ipv6.devconf_all->ndisc_notify)
1898+
if (READ_ONCE(idev->cnf.ndisc_notify) ||
1899+
READ_ONCE(net->ipv6.devconf_all->ndisc_notify))
19001900
ndisc_send_unsol_na(dev);
19011901
in6_dev_put(idev);
19021902
break;
@@ -1905,8 +1905,8 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event,
19051905
if (!idev)
19061906
evict_nocarrier = true;
19071907
else {
1908-
evict_nocarrier = idev->cnf.ndisc_evict_nocarrier &&
1909-
net->ipv6.devconf_all->ndisc_evict_nocarrier;
1908+
evict_nocarrier = READ_ONCE(idev->cnf.ndisc_evict_nocarrier) &&
1909+
READ_ONCE(net->ipv6.devconf_all->ndisc_evict_nocarrier);
19101910
in6_dev_put(idev);
19111911
}
19121912

net/ipv6/seg6_hmac.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -241,23 +241,25 @@ bool seg6_hmac_validate_skb(struct sk_buff *skb)
241241
struct sr6_tlv_hmac *tlv;
242242
struct ipv6_sr_hdr *srh;
243243
struct inet6_dev *idev;
244+
int require_hmac;
244245

245246
idev = __in6_dev_get(skb->dev);
246247

247248
srh = (struct ipv6_sr_hdr *)skb_transport_header(skb);
248249

249250
tlv = seg6_get_tlv_hmac(srh);
250251

252+
require_hmac = READ_ONCE(idev->cnf.seg6_require_hmac);
251253
/* mandatory check but no tlv */
252-
if (idev->cnf.seg6_require_hmac > 0 && !tlv)
254+
if (require_hmac > 0 && !tlv)
253255
return false;
254256

255257
/* no check */
256-
if (idev->cnf.seg6_require_hmac < 0)
258+
if (require_hmac < 0)
257259
return true;
258260

259261
/* check only if present */
260-
if (idev->cnf.seg6_require_hmac == 0 && !tlv)
262+
if (require_hmac == 0 && !tlv)
261263
return true;
262264

263265
/* now, seg6_require_hmac >= 0 && tlv */

0 commit comments

Comments
 (0)