Commit 2f0ff05a authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller
Browse files

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: 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 2aba913f
Loading
Loading
Loading
Loading
+26 −23
Original line number Diff line number Diff line
@@ -1557,15 +1557,17 @@ static inline int ipv6_saddr_preferred(int type)
	return 0;
}

static bool ipv6_use_optimistic_addr(struct net *net,
				     struct inet6_dev *idev)
static bool ipv6_use_optimistic_addr(const struct net *net,
				     const struct inet6_dev *idev)
{
#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
	if (!idev)
		return false;
	if (!net->ipv6.devconf_all->optimistic_dad && !idev->cnf.optimistic_dad)
	if (!READ_ONCE(net->ipv6.devconf_all->optimistic_dad) &&
	    !READ_ONCE(idev->cnf.optimistic_dad))
		return false;
	if (!net->ipv6.devconf_all->use_optimistic && !idev->cnf.use_optimistic)
	if (!READ_ONCE(net->ipv6.devconf_all->use_optimistic) &&
	    !READ_ONCE(idev->cnf.use_optimistic))
		return false;

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

static bool ipv6_allow_optimistic_dad(struct net *net,
				      struct inet6_dev *idev)
static bool ipv6_allow_optimistic_dad(const struct net *net,
				      const struct inet6_dev *idev)
{
#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
	if (!idev)
		return false;
	if (!net->ipv6.devconf_all->optimistic_dad && !idev->cnf.optimistic_dad)
	if (!READ_ONCE(net->ipv6.devconf_all->optimistic_dad) &&
	    !READ_ONCE(idev->cnf.optimistic_dad))
		return false;

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

#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
		if ((net->ipv6.devconf_all->optimistic_dad ||
		     in6_dev->cnf.optimistic_dad) &&
		if ((READ_ONCE(net->ipv6.devconf_all->optimistic_dad) ||
		     READ_ONCE(in6_dev->cnf.optimistic_dad)) &&
		    !net->ipv6.devconf_all->forwarding && sllao)
			cfg.ifa_flags |= IFA_F_OPTIMISTIC;
#endif
@@ -2733,7 +2736,7 @@ int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
		 */
		update_lft = !create && stored_lft;

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

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

		if (!_keep_addr)
			_keep_addr = idev->cnf.keep_addr_on_down;
			_keep_addr = READ_ONCE(idev->cnf.keep_addr_on_down);

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

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

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

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

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

		*((u32 *)ctl->data) = new_val;
		WRITE_ONCE(*((u32 *)ctl->data), new_val);
	}

out:
+9 −7
Original line number Diff line number Diff line
@@ -379,9 +379,8 @@ static int ipv6_srh_rcv(struct sk_buff *skb)

	idev = __in6_dev_get(skb->dev);

	accept_seg6 = net->ipv6.devconf_all->seg6_enabled;
	if (accept_seg6 > idev->cnf.seg6_enabled)
		accept_seg6 = idev->cnf.seg6_enabled;
	accept_seg6 = min(READ_ONCE(net->ipv6.devconf_all->seg6_enabled),
			  READ_ONCE(idev->cnf.seg6_enabled));

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

	if (idev && accept_source_route > idev->cnf.accept_source_route)
		accept_source_route = idev->cnf.accept_source_route;
	accept_source_route = READ_ONCE(net->ipv6.devconf_all->accept_source_route);

	if (idev)
		accept_source_route = min(accept_source_route,
					  READ_ONCE(idev->cnf.accept_source_route));

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

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

	/* Truncated Option header */
+4 −4
Original line number Diff line number Diff line
@@ -727,7 +727,7 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
		if (!skb->dev)
			raw16 = IOAM6_U16_UNAVAILABLE;
		else
			raw16 = (__force u16)__in6_dev_get(skb->dev)->cnf.ioam6_id;
			raw16 = (__force u16)READ_ONCE(__in6_dev_get(skb->dev)->cnf.ioam6_id);

		*(__be16 *)data = cpu_to_be16(raw16);
		data += sizeof(__be16);
@@ -735,7 +735,7 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
		if (skb_dst(skb)->dev->flags & IFF_LOOPBACK)
			raw16 = IOAM6_U16_UNAVAILABLE;
		else
			raw16 = (__force u16)__in6_dev_get(skb_dst(skb)->dev)->cnf.ioam6_id;
			raw16 = (__force u16)READ_ONCE(__in6_dev_get(skb_dst(skb)->dev)->cnf.ioam6_id);

		*(__be16 *)data = cpu_to_be16(raw16);
		data += sizeof(__be16);
@@ -822,7 +822,7 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
		if (!skb->dev)
			raw32 = IOAM6_U32_UNAVAILABLE;
		else
			raw32 = __in6_dev_get(skb->dev)->cnf.ioam6_id_wide;
			raw32 = READ_ONCE(__in6_dev_get(skb->dev)->cnf.ioam6_id_wide);

		*(__be32 *)data = cpu_to_be32(raw32);
		data += sizeof(__be32);
@@ -830,7 +830,7 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
		if (skb_dst(skb)->dev->flags & IFF_LOOPBACK)
			raw32 = IOAM6_U32_UNAVAILABLE;
		else
			raw32 = __in6_dev_get(skb_dst(skb)->dev)->cnf.ioam6_id_wide;
			raw32 = READ_ONCE(__in6_dev_get(skb_dst(skb)->dev)->cnf.ioam6_id_wide);

		*(__be32 *)data = cpu_to_be32(raw32);
		data += sizeof(__be32);
+1 −1
Original line number Diff line number Diff line
@@ -236,7 +236,7 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev,
	if (!ipv6_addr_is_multicast(&hdr->daddr) &&
	    (skb->pkt_type == PACKET_BROADCAST ||
	     skb->pkt_type == PACKET_MULTICAST) &&
	    idev->cnf.drop_unicast_in_l2_multicast) {
	    READ_ONCE(idev->cnf.drop_unicast_in_l2_multicast)) {
		SKB_DR_SET(reason, UNICAST_IN_L2_MULTICAST);
		goto err;
	}
+7 −7
Original line number Diff line number Diff line
@@ -159,9 +159,9 @@ static int unsolicited_report_interval(struct inet6_dev *idev)
	int iv;

	if (mld_in_v1_mode(idev))
		iv = idev->cnf.mldv1_unsolicited_report_interval;
		iv = READ_ONCE(idev->cnf.mldv1_unsolicited_report_interval);
	else
		iv = idev->cnf.mldv2_unsolicited_report_interval;
		iv = READ_ONCE(idev->cnf.mldv2_unsolicited_report_interval);

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

static int mld_force_mld_version(const struct inet6_dev *idev)
{
	const struct net *net = dev_net(idev->dev);
	int all_force;

	all_force = READ_ONCE(net->ipv6.devconf_all->force_mld_version);
	/* Normally, both are 0 here. If enforcement to a particular is
	 * being used, individual device enforcement will have a lower
	 * precedence over 'all' device (.../conf/all/force_mld_version).
	 */

	if (dev_net(idev->dev)->ipv6.devconf_all->force_mld_version != 0)
		return dev_net(idev->dev)->ipv6.devconf_all->force_mld_version;
	else
		return idev->cnf.force_mld_version;
	return all_force ?: READ_ONCE(idev->cnf.force_mld_version);
}

static bool mld_in_v2_mode_only(const struct inet6_dev *idev)
Loading