Index | Thread | Search

From:
Alexander Bluhm <bluhm@openbsd.org>
Subject:
ip sysctl atomic
To:
tech@openbsd.org
Date:
Tue, 30 Apr 2024 20:46:48 +0200

Download raw body.

Thread
Hi,

As general MP safe sysctls are currently not wanted, let's implement
it the other way around.

Access to global integer variables in net.inet.ip is made MP safe
with read once.  Some values are passed from ip_input() to ip_fragment()
with flags.  This keeps the view of IP processing consistent even
if another CPU changes the sysctl value.

I kept the sysctl code as it is, but added _mpsafe functions for
values that are used by multiple CPUs.

Using ip_defttl for IPv6 header has been fixed.  ip6_defhlim will
be made MP safe later.

ok?

bluhm

Index: kern/kern_sysctl.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/kern/kern_sysctl.c,v
diff -u -p -r1.427 kern_sysctl.c
--- kern/kern_sysctl.c	12 Apr 2024 16:07:09 -0000	1.427
+++ kern/kern_sysctl.c	30 Apr 2024 17:13:22 -0000
@@ -1021,6 +1021,41 @@ sysctl_int_bounded(void *oldp, size_t *o
 	return (0);
 }
 
+int
+sysctl_int_bounded_mpsafe(void *oldp, size_t *oldlenp, void *newp,
+    size_t newlen, int *valp, int minimum, int maximum)
+{
+	int oldval, newval;
+	int error;
+
+	/* read only */
+	if (newp != NULL && minimum > maximum)
+		return (EPERM);
+
+	if (oldp && *oldlenp < sizeof(int))
+		return (ENOMEM);
+	if (newp && newlen != sizeof(int))
+		return (EINVAL);
+	*oldlenp = sizeof(int);
+
+	/* copyin() may sleep, call it first */
+	if (newp) {
+		if ((error = copyin(newp, &newval, sizeof(int))))
+			return (error);
+		/* outside limits */
+		if (newval < minimum || maximum < newval)
+			return (EINVAL);
+	}
+	if (oldp) {
+		oldval = READ_ONCE(*valp);
+		if ((error = copyout(&oldval, oldp, sizeof(int))))
+			return (error);
+	}
+	if (newp)
+		WRITE_ONCE(*valp, newval);
+	return (0);
+}
+
 /*
  * Array of read-only or bounded integer values.
  */
@@ -1036,6 +1071,24 @@ sysctl_bounded_arr(const struct sysctl_b
 		if (valpp[i].mib == name[0]) {
 			return (sysctl_int_bounded(oldp, oldlenp, newp, newlen,
 			    valpp[i].var, valpp[i].minimum, valpp[i].maximum));
+		}
+	}
+	return (EOPNOTSUPP);
+}
+
+int
+sysctl_bounded_arr_mpsafe(const struct sysctl_bounded_args *valpp,
+    u_int valplen, int *name, u_int namelen, void *oldp, size_t *oldlenp,
+    void *newp, size_t newlen)
+{
+	u_int i;
+	if (namelen != 1)
+		return (ENOTDIR);
+	for (i = 0; i < valplen; ++i) {
+		if (valpp[i].mib == name[0]) {
+			return (sysctl_int_bounded_mpsafe(oldp, oldlenp, newp,
+			    newlen, valpp[i].var, valpp[i].minimum,
+			    valpp[i].maximum));
 		}
 	}
 	return (EOPNOTSUPP);
Index: net/if_etherip.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/net/if_etherip.c,v
diff -u -p -r1.55 if_etherip.c
--- net/if_etherip.c	13 Feb 2024 12:22:09 -0000	1.55
+++ net/if_etherip.c	30 Apr 2024 15:24:04 -0000
@@ -142,7 +142,7 @@ etherip_clone_create(struct if_clone *if
 	snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d",
 	    ifc->ifc_name, unit);
 
-	sc->sc_ttl = ip_defttl;
+	sc->sc_ttl = READ_ONCE(ip_defttl);
 	sc->sc_txhprio = IFQ_TOS2PRIO(IPTOS_PREC_ROUTINE); /* 0 */
 	sc->sc_rxhprio = IF_HDRPRIO_PACKET;
 	sc->sc_df = htons(0);
Index: net/if_gif.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/net/if_gif.c,v
diff -u -p -r1.137 if_gif.c
--- net/if_gif.c	1 Jan 2024 18:47:02 -0000	1.137
+++ net/if_gif.c	30 Apr 2024 15:24:04 -0000
@@ -154,7 +154,7 @@ gif_clone_create(struct if_clone *ifc, i
 	ifp = &sc->sc_if;
 
 	sc->sc_df = htons(0);
-	sc->sc_ttl = ip_defttl;
+	sc->sc_ttl = READ_ONCE(ip_defttl);
 	sc->sc_txhprio = IF_HDRPRIO_PAYLOAD;
 	sc->sc_rxhprio = IF_HDRPRIO_PAYLOAD;
 	sc->sc_ecn = ECN_ALLOWED;
Index: net/if_gre.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/net/if_gre.c,v
diff -u -p -r1.178 if_gre.c
--- net/if_gre.c	23 Dec 2023 10:52:54 -0000	1.178
+++ net/if_gre.c	30 Apr 2024 15:24:04 -0000
@@ -582,7 +582,7 @@ gre_clone_create(struct if_clone *ifc, i
 	ifp->if_ioctl = gre_ioctl;
 	ifp->if_rtrequest = p2p_rtrequest;
 
-	sc->sc_tunnel.t_ttl = ip_defttl;
+	sc->sc_tunnel.t_ttl = READ_ONCE(ip_defttl);
 	sc->sc_tunnel.t_txhprio = IF_HDRPRIO_PAYLOAD;
 	sc->sc_tunnel.t_rxhprio = IF_HDRPRIO_PACKET;
 	sc->sc_tunnel.t_df = htons(0);
@@ -653,7 +653,7 @@ mgre_clone_create(struct if_clone *ifc, 
 	ifp->if_start = mgre_start;
 	ifp->if_ioctl = mgre_ioctl;
 
-	sc->sc_tunnel.t_ttl = ip_defttl;
+	sc->sc_tunnel.t_ttl = READ_ONCE(ip_defttl);
 	sc->sc_tunnel.t_txhprio = IF_HDRPRIO_PAYLOAD;
 	sc->sc_tunnel.t_rxhprio = IF_HDRPRIO_PACKET;
 	sc->sc_tunnel.t_df = htons(0);
@@ -707,7 +707,7 @@ egre_clone_create(struct if_clone *ifc, 
 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
 	ether_fakeaddr(ifp);
 
-	sc->sc_tunnel.t_ttl = ip_defttl;
+	sc->sc_tunnel.t_ttl = READ_ONCE(ip_defttl);
 	sc->sc_tunnel.t_txhprio = 0;
 	sc->sc_tunnel.t_rxhprio = IF_HDRPRIO_PACKET;
 	sc->sc_tunnel.t_df = htons(0);
@@ -842,7 +842,7 @@ eoip_clone_create(struct if_clone *ifc, 
 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
 	ether_fakeaddr(ifp);
 
-	sc->sc_tunnel.t_ttl = ip_defttl;
+	sc->sc_tunnel.t_ttl = READ_ONCE(ip_defttl);
 	sc->sc_tunnel.t_txhprio = 0;
 	sc->sc_tunnel.t_rxhprio = IF_HDRPRIO_PACKET;
 	sc->sc_tunnel.t_df = htons(0);
@@ -3006,7 +3006,8 @@ gre_keepalive_send(void *arg)
 	SipHash24_Update(&ctx, &gk->gk_random, sizeof(gk->gk_random));
 	SipHash24_Final(gk->gk_digest, &ctx);
 
-	ttl = sc->sc_tunnel.t_ttl == -1 ? ip_defttl : sc->sc_tunnel.t_ttl;
+	ttl = sc->sc_tunnel.t_ttl == -1 ? READ_ONCE(ip_defttl) :
+	    sc->sc_tunnel.t_ttl;
 
 	m->m_pkthdr.pf.prio = sc->sc_if.if_llprio;
 	tos = gre_l3_tos(&sc->sc_tunnel, m, IFQ_PRIO2TOS(m->m_pkthdr.pf.prio));
Index: net/pf.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/net/pf.c,v
diff -u -p -r1.1194 pf.c
--- net/pf.c	12 Apr 2024 16:07:09 -0000	1.1194
+++ net/pf.c	30 Apr 2024 16:42:13 -0000
@@ -7960,12 +7960,17 @@ done:
 		switch (pd.naf) {
 		case AF_INET:
 			if (pd.dir == PF_IN) {
-				if (ipforwarding == 0) {
+				int flags;
+
+				if (READ_ONCE(ipforwarding) == 0) {
 					ipstat_inc(ips_cantforward);
 					action = PF_DROP;
 					break;
 				}
-				ip_forward(pd.m, ifp, NULL, 1);
+				flags = IP_FORWARDING | IP_REDIRECT;
+				if (READ_ONCE(ip_directedbcast))
+					SET(flags, IP_ALLOWBROADCAST);
+				ip_forward(pd.m, ifp, NULL, flags);
 			} else
 				ip_output(pd.m, NULL, NULL, 0, NULL, NULL, 0);
 			break;
Index: netinet/if_ether.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/if_ether.c,v
diff -u -p -r1.267 if_ether.c
--- netinet/if_ether.c	18 Dec 2023 13:30:44 -0000	1.267
+++ netinet/if_ether.c	30 Apr 2024 15:33:51 -0000
@@ -386,7 +386,7 @@ arpresolve(struct ifnet *ifp, struct rte
 
 		/* refresh ARP entry when timeout gets close */
 		if (rt->rt_expire != 0 &&
-		    rt->rt_expire - arpt_keep / 8 < uptime) {
+		    rt->rt_expire - READ_ONCE(arpt_keep) / 8 < uptime) {
 
 			mtx_enter(&arp_mtx);
 			la = (struct llinfo_arp *)rt->rt_llinfo;
@@ -449,7 +449,7 @@ arpresolve(struct ifnet *ifp, struct rte
 				refresh = 1;
 			else {
 				reject = RTF_REJECT;
-				rt->rt_expire += arpt_down;
+				rt->rt_expire += READ_ONCE(arpt_down);
 				la->la_asked = 0;
 				la->la_refreshed = 0;
 				atomic_sub_int(&la_hold_total,
@@ -711,7 +711,7 @@ arpcache(struct ifnet *ifp, struct ether
 	sdl->sdl_alen = sizeof(ea->arp_sha);
 	memcpy(LLADDR(sdl), ea->arp_sha, sizeof(ea->arp_sha));
 	if (rt->rt_expire)
-		rt->rt_expire = uptime + arpt_keep;
+		rt->rt_expire = uptime + READ_ONCE(arpt_keep);
 	rt->rt_flags &= ~RTF_REJECT;
 
 	/* Notify userland that an ARP resolution has been done. */
Index: netinet/in_pcb.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/in_pcb.c,v
diff -u -p -r1.302 in_pcb.c
--- netinet/in_pcb.c	19 Apr 2024 10:13:58 -0000	1.302
+++ netinet/in_pcb.c	30 Apr 2024 15:24:04 -0000
@@ -108,10 +108,10 @@ const union inpaddru zeroin46_addr;
  * These configure the range of local port addresses assigned to
  * "unspecified" outgoing connections/packets/whatever.
  */
-int ipport_firstauto = IPPORT_RESERVED;
-int ipport_lastauto = IPPORT_USERRESERVED;
-int ipport_hifirstauto = IPPORT_HIFIRSTAUTO;
-int ipport_hilastauto = IPPORT_HILASTAUTO;
+int ipport_firstauto = IPPORT_RESERVED;		/* [a] */
+int ipport_lastauto = IPPORT_USERRESERVED;	/* [a] */
+int ipport_hifirstauto = IPPORT_HIFIRSTAUTO;	/* [a] */
+int ipport_hilastauto = IPPORT_HILASTAUTO;	/* [a] */
 
 struct baddynamicports baddynamicports;
 struct baddynamicports rootonlyports;
@@ -452,16 +452,16 @@ in_pcbpickport(u_int16_t *lport, const v
 	MUTEX_ASSERT_LOCKED(&table->inpt_mtx);
 
 	if (inp->inp_flags & INP_HIGHPORT) {
-		first = ipport_hifirstauto;	/* sysctl */
-		last = ipport_hilastauto;
+		first = READ_ONCE(ipport_hifirstauto);	/* sysctl */
+		last = READ_ONCE(ipport_hilastauto);
 	} else if (inp->inp_flags & INP_LOWPORT) {
 		if (suser(p))
 			return (EACCES);
 		first = IPPORT_RESERVED-1; /* 1023 */
 		last = 600;		   /* not IPPORT_RESERVED/2 */
 	} else {
-		first = ipport_firstauto;	/* sysctl */
-		last = ipport_lastauto;
+		first = READ_ONCE(ipport_firstauto);	/* sysctl */
+		last = READ_ONCE(ipport_lastauto);
 	}
 	if (first < last) {
 		lower = first;
Index: netinet/ip_icmp.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_icmp.c,v
diff -u -p -r1.192 ip_icmp.c
--- netinet/ip_icmp.c	16 Sep 2023 09:33:27 -0000	1.192
+++ netinet/ip_icmp.c	30 Apr 2024 15:33:51 -0000
@@ -589,7 +589,7 @@ reflect:
 		struct sockaddr_in ssrc;
 		struct rtentry *newrt = NULL;
 
-		if (icmp_rediraccept == 0 || ipforwarding == 1)
+		if (icmp_rediraccept == 0 || READ_ONCE(ipforwarding) == 1)
 			goto freeit;
 		if (code > 3)
 			goto badcode;
Index: netinet/ip_input.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_input.c,v
diff -u -p -r1.393 ip_input.c
--- netinet/ip_input.c	16 Apr 2024 12:56:39 -0000	1.393
+++ netinet/ip_input.c	30 Apr 2024 17:13:20 -0000
@@ -83,13 +83,20 @@
 #include <netinet/ip_carp.h>
 #endif
 
+/*
+ * Locks used to protect global variables in this file:
+ *	I	immutable after creation
+ *	a	atomic operations
+ *	N	net lock
+ */
+
 /* values controllable via sysctl */
-int	ipforwarding = 0;
-int	ipmforwarding = 0;
-int	ipmultipath = 0;
-int	ipsendredirects = 1;
+int	ipforwarding = 0;			/* [a] */
+int	ipmforwarding = 0;			/* [a] */
+int	ipmultipath = 0;			/* [N] */
+int	ipsendredirects = 1;			/* [a] */
 int	ip_dosourceroute = 0;
-int	ip_defttl = IPDEFTTL;
+int	ip_defttl = IPDEFTTL;			/* [a] */
 int	ip_mtudisc = 1;
 int	ip_mtudisc_timeout = IPMTUDISCTIMEOUT;
 int	ip_directedbcast = 0;
@@ -101,7 +108,7 @@ struct mutex	ipq_mutex = MUTEX_INITIALIZ
 LIST_HEAD(, ipq) ipq;
 
 /* Keep track of memory used for reassembly */
-int	ip_maxqueue = 300;
+int	ip_maxqueue = 300;	/* [a] maximum fragments in reassembly queue */
 int	ip_frags = 0;
 
 const struct sysctl_bounded_args ipctl_vars[] = {
@@ -137,8 +144,8 @@ static struct mbuf_queue	ipsendraw_mq;
 extern struct niqueue		arpinq;
 
 int	ip_ours(struct mbuf **, int *, int, int);
-int	ip_dooptions(struct mbuf *, struct ifnet *);
-int	in_ouraddr(struct mbuf *, struct ifnet *, struct route *);
+int	ip_dooptions(struct mbuf *, struct ifnet *, int);
+int	in_ouraddr(struct mbuf *, struct ifnet *, struct route *, int);
 
 int		ip_fragcheck(struct mbuf **, int *);
 struct mbuf *	ip_reass(struct ipqent *, struct ipq *);
@@ -431,7 +438,7 @@ ip_input_if(struct mbuf **mp, int *offp,
 #if NPF > 0
 	struct in_addr odst;
 #endif
-	int pfrdr = 0;
+	int flags = 0;
 
 	KASSERT(*offp == 0);
 
@@ -461,9 +468,15 @@ ip_input_if(struct mbuf **mp, int *offp,
 		goto bad;
 
 	ip = mtod(m, struct ip *);
-	pfrdr = odst.s_addr != ip->ip_dst.s_addr;
+	if (odst.s_addr != ip->ip_dst.s_addr)
+		SET(flags, IP_REDIRECT);
 #endif
 
+	if (READ_ONCE(ipforwarding) != 0)
+		SET(flags, IP_FORWARDING);
+	if (READ_ONCE(ip_directedbcast))
+		SET(flags, IP_ALLOWBROADCAST);
+
 	hlen = ip->ip_hl << 2;
 
 	/*
@@ -472,7 +485,7 @@ ip_input_if(struct mbuf **mp, int *offp,
 	 * error was detected (causing an icmp message
 	 * to be sent and the original packet to be freed).
 	 */
-	if (hlen > sizeof (struct ip) && ip_dooptions(m, ifp)) {
+	if (hlen > sizeof (struct ip) && ip_dooptions(m, ifp, flags)) {
 		m = *mp = NULL;
 		goto bad;
 	}
@@ -483,7 +496,7 @@ ip_input_if(struct mbuf **mp, int *offp,
 		goto out;
 	}
 
-	switch(in_ouraddr(m, ifp, &ro)) {
+	switch(in_ouraddr(m, ifp, &ro, flags)) {
 	case 2:
 		goto bad;
 	case 1:
@@ -500,7 +513,7 @@ ip_input_if(struct mbuf **mp, int *offp,
 		m->m_flags |= M_MCAST;
 
 #ifdef MROUTING
-		if (ipmforwarding && ip_mrouter[ifp->if_rdomain]) {
+		if (READ_ONCE(ipmforwarding) && ip_mrouter[ifp->if_rdomain]) {
 			int error;
 
 			if (m->m_flags & M_EXT) {
@@ -565,7 +578,7 @@ ip_input_if(struct mbuf **mp, int *offp,
 	/*
 	 * Not for us; forward if possible and desirable.
 	 */
-	if (ipforwarding == 0) {
+	if (!ISSET(flags, IP_FORWARDING)) {
 		ipstat_inc(ips_cantforward);
 		goto bad;
 	}
@@ -585,7 +598,7 @@ ip_input_if(struct mbuf **mp, int *offp,
 	}
 #endif /* IPSEC */
 
-	ip_forward(m, ifp, &ro, pfrdr);
+	ip_forward(m, ifp, &ro, flags);
 	*mp = NULL;
 	return IPPROTO_DONE;
  bad:
@@ -666,7 +679,7 @@ ip_fragcheck(struct mbuf **mp, int *offp
 		 */
 		if (mff || ip->ip_off) {
 			ipstat_inc(ips_fragments);
-			if (ip_frags + 1 > ip_maxqueue) {
+			if (ip_frags + 1 > READ_ONCE(ip_maxqueue)) {
 				ip_flush();
 				ipstat_inc(ips_rcvmemdrop);
 				goto bad;
@@ -806,7 +819,7 @@ ip_deliver(struct mbuf **mp, int *offp, 
 #undef IPSTAT_INC
 
 int
-in_ouraddr(struct mbuf *m, struct ifnet *ifp, struct route *ro)
+in_ouraddr(struct mbuf *m, struct ifnet *ifp, struct route *ro, int flags)
 {
 	struct rtentry		*rt;
 	struct ip		*ip;
@@ -836,7 +849,8 @@ in_ouraddr(struct mbuf *m, struct ifnet 
 		 * if it is received on the interface with that address.
 		 */
 		if (ISSET(rt->rt_flags, RTF_BROADCAST) &&
-		    (!ip_directedbcast || rt->rt_ifidx == ifp->if_index)) {
+		    (!ISSET(flags, IP_ALLOWBROADCAST) ||
+		    rt->rt_ifidx == ifp->if_index)) {
 			match = 1;
 
 			/* Make sure M_BCAST is set */
@@ -875,7 +889,8 @@ in_ouraddr(struct mbuf *m, struct ifnet 
 				break;
 			}
 		}
-	} else if (ipforwarding == 0 && rt->rt_ifidx != ifp->if_index &&
+	} else if (!ISSET(flags, IP_FORWARDING) &&
+	    rt->rt_ifidx != ifp->if_index &&
 	    !((ifp->if_flags & IFF_LOOPBACK) || (ifp->if_type == IFT_ENC) ||
 	    (m->m_pkthdr.pf.flags & PF_TAG_TRANSLATE_LOCALHOST))) {
 		/* received on wrong interface. */
@@ -1131,11 +1146,13 @@ ip_slowtimo(void)
 void
 ip_flush(void)
 {
-	int max = 50;
+	int limit, max = 50;
 
 	MUTEX_ASSERT_LOCKED(&ipq_mutex);
 
-	while (!LIST_EMPTY(&ipq) && ip_frags > ip_maxqueue * 3 / 4 && --max) {
+	limit = READ_ONCE(ip_maxqueue) * 3 / 4;
+
+	while (!LIST_EMPTY(&ipq) && ip_frags > limit && --max) {
 		ipstat_inc(ips_fragdropped);
 		ip_freef(LIST_FIRST(&ipq));
 	}
@@ -1149,7 +1166,7 @@ ip_flush(void)
  * 0 if the packet should be processed further.
  */
 int
-ip_dooptions(struct mbuf *m, struct ifnet *ifp)
+ip_dooptions(struct mbuf *m, struct ifnet *ifp, int flags)
 {
 	struct ip *ip = mtod(m, struct ip *);
 	unsigned int rtableid = m->m_pkthdr.ph_rtableid;
@@ -1370,8 +1387,8 @@ ip_dooptions(struct mbuf *m, struct ifne
 		}
 	}
 	KERNEL_UNLOCK();
-	if (forward && ipforwarding > 0) {
-		ip_forward(m, ifp, NULL, 1);
+	if (forward && ISSET(flags, IP_FORWARDING)) {
+		ip_forward(m, ifp, NULL, flags | IP_REDIRECT);
 		return (1);
 	}
 	return (0);
@@ -1521,7 +1538,7 @@ const u_char inetctlerrmap[PRC_NCMDS] = 
  * via a source route.
  */
 void
-ip_forward(struct mbuf *m, struct ifnet *ifp, struct route *ro, int srcrt)
+ip_forward(struct mbuf *m, struct ifnet *ifp, struct route *ro, int flags)
 {
 	struct mbuf mfake, *mcopy;
 	struct ip *ip = mtod(m, struct ip *);
@@ -1587,7 +1604,7 @@ ip_forward(struct mbuf *m, struct ifnet 
 	if ((rt->rt_ifidx == ifp->if_index) &&
 	    (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 &&
 	    satosin(rt_key(rt))->sin_addr.s_addr != 0 &&
-	    ipsendredirects && !srcrt &&
+	    READ_ONCE(ipsendredirects) && !ISSET(flags, IP_REDIRECT) &&
 	    !arpproxy(satosin(rt_key(rt))->sin_addr, m->m_pkthdr.ph_rtableid)) {
 		if ((ip->ip_src.s_addr & ifatoia(rt->rt_ifa)->ia_netmask) ==
 		    ifatoia(rt->rt_ifa)->ia_net) {
@@ -1601,9 +1618,7 @@ ip_forward(struct mbuf *m, struct ifnet 
 		}
 	}
 
-	error = ip_output(m, NULL, ro,
-	    (IP_FORWARDING | (ip_directedbcast ? IP_ALLOWBROADCAST : 0)),
-	    NULL, NULL, 0);
+	error = ip_output(m, NULL, ro, flags | IP_FORWARDING, NULL, NULL, 0);
 	rt = ro->ro_rt;
 	if (error)
 		ipstat_inc(ips_cantforward);
@@ -1780,10 +1795,9 @@ ip_sysctl(int *name, u_int namelen, void
 		NET_UNLOCK();
 		return (error);
 	default:
-		NET_LOCK();
-		error = sysctl_bounded_arr(ipctl_vars, nitems(ipctl_vars),
-		    name, namelen, oldp, oldlenp, newp, newlen);
-		NET_UNLOCK();
+		error = sysctl_bounded_arr_mpsafe(ipctl_vars,
+		    nitems(ipctl_vars), name, namelen, oldp, oldlenp, newp,
+		    newlen);
 		return (error);
 	}
 	/* NOTREACHED */
Index: netinet/ip_ipip.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_ipip.c,v
diff -u -p -r1.101 ip_ipip.c
--- netinet/ip_ipip.c	11 Feb 2024 01:27:45 -0000	1.101
+++ netinet/ip_ipip.c	30 Apr 2024 15:24:04 -0000
@@ -381,7 +381,7 @@ ipip_output(struct mbuf **mp, struct tdb
 		ipo->ip_v = IPVERSION;
 		ipo->ip_hl = 5;
 		ipo->ip_len = htons(m->m_pkthdr.len);
-		ipo->ip_ttl = ip_defttl;
+		ipo->ip_ttl = READ_ONCE(ip_defttl);
 		ipo->ip_sum = 0;
 		ipo->ip_src = tdb->tdb_src.sin.sin_addr;
 		ipo->ip_dst = tdb->tdb_dst.sin.sin_addr;
@@ -481,7 +481,7 @@ ipip_output(struct mbuf **mp, struct tdb
 		ip6o->ip6_vfc &= ~IPV6_VERSION_MASK;
 		ip6o->ip6_vfc |= IPV6_VERSION;
 		ip6o->ip6_plen = htons(m->m_pkthdr.len - sizeof(*ip6o));
-		ip6o->ip6_hlim = ip_defttl;
+		ip6o->ip6_hlim = ip6_defhlim;
 		in6_embedscope(&ip6o->ip6_src, &tdb->tdb_src.sin6, NULL, NULL);
 		in6_embedscope(&ip6o->ip6_dst, &tdb->tdb_dst.sin6, NULL, NULL);
 
Index: netinet/ip_mroute.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_mroute.c,v
diff -u -p -r1.142 ip_mroute.c
--- netinet/ip_mroute.c	6 Apr 2024 14:23:27 -0000	1.142
+++ netinet/ip_mroute.c	30 Apr 2024 15:24:04 -0000
@@ -98,7 +98,7 @@ int mcast_debug = 1;
 struct socket	*ip_mrouter[RT_TABLEID_MAX + 1];
 struct rttimer_queue ip_mrouterq;
 uint64_t	 mrt_count[RT_TABLEID_MAX + 1];
-int		ip_mrtproto = IGMP_DVMRP;    /* for netstat only */
+int		ip_mrtproto = IGMP_DVMRP;    /* [I] for netstat only */
 
 struct mrtstat	mrtstat;
 
Index: netinet/ip_output.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_output.c,v
diff -u -p -r1.398 ip_output.c
--- netinet/ip_output.c	17 Apr 2024 20:48:51 -0000	1.398
+++ netinet/ip_output.c	30 Apr 2024 15:33:51 -0000
@@ -326,7 +326,8 @@ reroute:
 			 * above, will be forwarded by the ip_input() routine,
 			 * if necessary.
 			 */
-			if (ipmforwarding && ip_mrouter[ifp->if_rdomain] &&
+			if (READ_ONCE(ipmforwarding) &&
+			    ip_mrouter[ifp->if_rdomain] &&
 			    (flags & IP_FORWARDING) == 0) {
 				int rv;
 
@@ -428,7 +429,8 @@ sendit:
 #endif
 
 #ifdef IPSEC
-	if (ipsec_in_use && (flags & IP_FORWARDING) && (ipforwarding == 2) &&
+	if (ipsec_in_use && (flags & IP_FORWARDING) &&
+	    (READ_ONCE(ipforwarding) == 2) &&
 	    (m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL) == NULL)) {
 		error = EHOSTUNREACH;
 		goto bad;
@@ -907,7 +909,8 @@ ip_ctloutput(int op, struct socket *so, 
 					if (optval > 0 && optval <= MAXTTL)
 						inp->inp_ip.ip_ttl = optval;
 					else if (optval == -1)
-						inp->inp_ip.ip_ttl = ip_defttl;
+						inp->inp_ip.ip_ttl =	
+						    READ_ONCE(ip_defttl);
 					else
 						error = EINVAL;
 					break;
@@ -1123,7 +1126,7 @@ ip_ctloutput(int op, struct socket *so, 
 				break;
 
 			case IP_IPDEFTTL:
-				optval = ip_defttl;
+				optval = READ_ONCE(ip_defttl);
 				break;
 
 #define	OPTBIT(bit)	(inp->inp_flags & bit ? 1 : 0)
Index: netinet/ip_var.h
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/ip_var.h,v
diff -u -p -r1.117 ip_var.h
--- netinet/ip_var.h	17 Apr 2024 20:48:51 -0000	1.117
+++ netinet/ip_var.h	30 Apr 2024 16:41:15 -0000
@@ -206,6 +206,7 @@ struct ipoffnxt {
 /* flags passed to ip_output */
 #define	IP_FORWARDING		0x1		/* most of ip header exists */
 #define	IP_RAWOUTPUT		0x2		/* raw ip header exists */
+#define	IP_REDIRECT		0x4	/* redirected by pf or source route */
 #define	IP_ALLOWBROADCAST	SO_BROADCAST	/* can send broadcast packets */
 #define	IP_MTUDISC		0x0800		/* pmtu discovery, set DF */
 
@@ -226,6 +227,7 @@ extern int ipforwarding;		/* enable IP f
 extern int ipmforwarding;		/* enable multicast forwarding */
 #endif
 extern int ipmultipath;			/* enable multipath routing */
+extern int ip_directedbcast;		/* accept all broadcast packets */
 extern unsigned int la_hold_total;
 
 extern const struct pr_usrreqs rip_usrreqs;
Index: netinet/tcp_input.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/tcp_input.c,v
diff -u -p -r1.405 tcp_input.c
--- netinet/tcp_input.c	17 Apr 2024 20:48:51 -0000	1.405
+++ netinet/tcp_input.c	30 Apr 2024 15:24:04 -0000
@@ -4143,7 +4143,7 @@ syn_cache_respond(struct syn_cache *sc, 
 	switch (sc->sc_src.sa.sa_family) {
 	case AF_INET:
 		ip->ip_len = htons(tlen);
-		ip->ip_ttl = inp ? inp->inp_ip.ip_ttl : ip_defttl;
+		ip->ip_ttl = inp ? inp->inp_ip.ip_ttl : READ_ONCE(ip_defttl);
 		if (inp != NULL)
 			ip->ip_tos = inp->inp_ip.ip_tos;
 
Index: netinet/tcp_subr.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/tcp_subr.c,v
diff -u -p -r1.201 tcp_subr.c
--- netinet/tcp_subr.c	17 Apr 2024 20:48:51 -0000	1.201
+++ netinet/tcp_subr.c	30 Apr 2024 15:24:04 -0000
@@ -411,7 +411,7 @@ tcp_respond(struct tcpcb *tp, caddr_t te
 #endif /* INET6 */
 	case AF_INET:
 		ip->ip_len = htons(tlen);
-		ip->ip_ttl = ip_defttl;
+		ip->ip_ttl = READ_ONCE(ip_defttl);
 		ip->ip_tos = 0;
 		ip_output(m, NULL,
 		    tp ? &tp->t_inpcb->inp_route : NULL,
@@ -471,7 +471,7 @@ tcp_newtcpcb(struct inpcb *inp, int wait
 #endif
 	{
 		tp->pf = PF_INET;
-		inp->inp_ip.ip_ttl = ip_defttl;
+		inp->inp_ip.ip_ttl = READ_ONCE(ip_defttl);
 	}
 
 	inp->inp_ppcb = (caddr_t)tp;
Index: netinet/udp_usrreq.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/udp_usrreq.c,v
diff -u -p -r1.320 udp_usrreq.c
--- netinet/udp_usrreq.c	17 Apr 2024 20:48:51 -0000	1.320
+++ netinet/udp_usrreq.c	30 Apr 2024 15:24:04 -0000
@@ -1121,7 +1121,7 @@ udp_attach(struct socket *so, int proto,
 		sotoinpcb(so)->inp_ipv6.ip6_hlim = ip6_defhlim;
 	else
 #endif
-		sotoinpcb(so)->inp_ip.ip_ttl = ip_defttl;
+		sotoinpcb(so)->inp_ip.ip_ttl = READ_ONCE(ip_defttl);
 	return 0;
 }
 
Index: sys/sysctl.h
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/sys/sysctl.h,v
diff -u -p -r1.235 sysctl.h
--- sys/sysctl.h	1 Oct 2023 15:58:12 -0000	1.235
+++ sys/sysctl.h	30 Apr 2024 17:13:49 -0000
@@ -1059,7 +1059,11 @@ int sysctl_int(void *, size_t *, void *,
 int sysctl_rdint(void *, size_t *, void *, int);
 int sysctl_securelevel_int(void *, size_t *, void *, size_t, int *);
 int sysctl_int_bounded(void *, size_t *, void *, size_t, int *, int, int);
+int sysctl_int_bounded_mpsafe(void *, size_t *, void *, size_t, int *, int,
+    int);
 int sysctl_bounded_arr(const struct sysctl_bounded_args *, u_int,
+    int *, u_int, void *, size_t *, void *, size_t);
+int sysctl_bounded_arr_mpsafe(const struct sysctl_bounded_args *, u_int,
     int *, u_int, void *, size_t *, void *, size_t);
 int sysctl_quad(void *, size_t *, void *, size_t, int64_t *);
 int sysctl_rdquad(void *, size_t *, void *, int64_t);