Download raw body.
udp, sysctl: unlock UDPCTL_ROOTONLY and UDPCTL_BADDYNAMIC
On Sat, May 10, 2025 at 06:24:24AM +0300, Vitaliy Makkoveev wrote:
> sysctl(2) is not the hot path, but I want to remove kernel lock with
> vslock() and relax netlock pressure here.
>
> Use temporary buffer to exchange data with the userland. So we need to
> take exclusive netlock only if we modify values. The shared netlock is
> still required even if we read values, but it doesn't stop packets
> processing in the most paths.
>
> I have more complicated version of this diff which introduces the mutex
> for `baddynamicports' protection, so the netlock could be avoided here.
> However this requires to take this mutex in the in_pcbbind() path and I
> see no reason to do this now. sysctl(2) is not the hot path, the most
> common read-only case doesn't stop the netstack and doesn't take kernel
> lock, I'm fine with it. I like to use producer/consumer locking here
> instead of mutexes.
Some style nits.
> + const size_t buflen = bufitems * sizeof(u_int32_t);
> + uint32_t *buf;
We prefer the newer uint32_t over u_int32_t. Please use that
consistently here.
> + if ((error == 0) && newp) {
The extra () within an if condition tell the compler not to issue
an warning if = is uses instead of ==.
if ((error = 0) && newp) compiles perfectly
if (error = 0 && newp) gives compiler warning
if (error == 0 && newp) should be used here
OK bluhm@
> The TCP related `rootonlyports' and `baddynamicports' could be
> refactored in the same way.
>
> Index: sys/netinet/udp_usrreq.c
> ===================================================================
> RCS file: /cvs/src/sys/netinet/udp_usrreq.c,v
> retrieving revision 1.336
> diff -u -p -r1.336 udp_usrreq.c
> --- sys/netinet/udp_usrreq.c 11 Mar 2025 15:31:03 -0000 1.336
> +++ sys/netinet/udp_usrreq.c 10 May 2025 02:23:08 -0000
> @@ -174,7 +174,6 @@ void udp_sbappend(struct inpcb *, struct
> u_int32_t, struct netstack *);
> int udp_output(struct inpcb *, struct mbuf *, struct mbuf *, struct mbuf *);
> void udp_notify(struct inpcb *, int);
> -int udp_sysctl_locked(int *, u_int, void *, size_t *, void *, size_t);
> int udp_sysctl_udpstat(void *, size_t *, void *);
>
> #ifndef UDB_INITIAL_HASH_SIZE
> @@ -1278,16 +1277,37 @@ udp_sysctl(int *name, u_int namelen, voi
> return (ENOTDIR);
>
> switch (name[0]) {
> - case UDPCTL_BADDYNAMIC:
> - case UDPCTL_ROOTONLY: {
> - size_t savelen = *oldlenp;
> + case UDPCTL_ROOTONLY:
> + if (newp && (int)atomic_load_int(&securelevel) > 0)
> + return (EPERM);
> + /* FALLTHROUGH */
> + case UDPCTL_BADDYNAMIC: {
> + struct baddynamicports *ports = (name[0] == UDPCTL_ROOTONLY ?
> + &rootonlyports : &baddynamicports);
> + const size_t bufitems = DP_MAPSIZE;
> + const size_t buflen = bufitems * sizeof(u_int32_t);
> + size_t i;
> + uint32_t *buf;
> int error;
>
> - if ((error = sysctl_vslock(oldp, savelen)))
> - return (error);
> - error = udp_sysctl_locked(name, namelen, oldp, oldlenp,
> - newp, newlen);
> - sysctl_vsunlock(oldp, savelen);
> + buf = malloc(buflen, M_SYSCTL, M_WAITOK | M_ZERO);
> +
> + NET_LOCK_SHARED();
> + for (i = 0; i < bufitems; ++i)
> + buf[i] = ports->udp[i];
> + NET_UNLOCK_SHARED();
> +
> + error = sysctl_struct(oldp, oldlenp, newp, newlen,
> + buf, buflen);
> +
> + if ((error == 0) && newp) {
> + NET_LOCK();
> + for (i = 0; i < bufitems; ++i)
> + ports->udp[i] = buf[i];
> + NET_UNLOCK();
> + }
> +
> + free(buf, M_SYSCTL, buflen);
>
> return (error);
> }
> @@ -1302,33 +1322,6 @@ udp_sysctl(int *name, u_int namelen, voi
> name, namelen, oldp, oldlenp, newp, newlen));
> }
> /* NOTREACHED */
> -}
> -
> -int
> -udp_sysctl_locked(int *name, u_int namelen, void *oldp, size_t *oldlenp,
> - void *newp, size_t newlen)
> -{
> - int error = ENOPROTOOPT;
> -
> - switch (name[0]) {
> - case UDPCTL_BADDYNAMIC:
> - NET_LOCK();
> - error = sysctl_struct(oldp, oldlenp, newp, newlen,
> - baddynamicports.udp, sizeof(baddynamicports.udp));
> - NET_UNLOCK();
> - break;
> -
> - case UDPCTL_ROOTONLY:
> - if (newp && securelevel > 0)
> - return (EPERM);
> - NET_LOCK();
> - error = sysctl_struct(oldp, oldlenp, newp, newlen,
> - rootonlyports.udp, sizeof(rootonlyports.udp));
> - NET_UNLOCK();
> - break;
> - }
> -
> - return (error);
> }
>
> int
udp, sysctl: unlock UDPCTL_ROOTONLY and UDPCTL_BADDYNAMIC