Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 22 Jun 1997 07:20:04 -0700 (PDT)
From:      sthaug@nethelp.no
To:        freebsd-bugs
Subject:   Re: kern/3925: SO_SNDLOWAT of 0 causes kernel to use 99% of CPU time on TCP send
Message-ID:  <199706221420.HAA03342@hub.freebsd.org>

next in thread | raw e-mail | index | archive | help
The following reply was made to PR kern/3925; it has been noted by GNATS.

From: sthaug@nethelp.no
To: freebsd-gnats-submit@freebsd.org
Cc: sthaug@nethelp.no
Subject: Re: kern/3925: SO_SNDLOWAT of 0 causes kernel to use 99% of CPU time on TCP send
Date: Sun, 22 Jun 1997 16:17:13 +0200

 A quick followup to my bug report: The bug appears in NetBSD also. One of
 the NetBSD persons here made a more thorough analysis of the problem. Here
 is the corresponding NetBSD problem report.
 
 Steinar Haug, Nethelp consulting, sthaug@nethelp.no
 ----------------------------------------------------------------------
 Subject: Setting SO_SNDLOWAT to 0 causes busy-wait inside kernel
 From: Havard Eidnes <he@vader.runit.sintef.no>
 To: gnats-bugs@gnats.netbsd.org
 Date: Sun, 22 Jun 1997 15:45:56 +0200 (MEST)
 
 
 >Submitter-Id:	net
 >Originator:	Havard Eidnes
 >Organization:	SINTEF RUNIT
 >Confidential:	no
 >Synopsis:	Setting SO_SNDLOWAT to 0 causes busy-wait inside kernel
 >Severity:	critical
 >Priority:	high
 >Category:	kern
 >Class:		sw-bug
 >Release:	NetBSD-1.2.1 (and newer versions too)
 >Environment:   System: NetBSD vader.runit.sintef.no 1.2G NetBSD 1.2G (VADER) #2: Mon Jun 16 21:58:48 MEST 1997 he@vader.runit.sintef.no:/usr/src/sys/arch/i386/compile/VADER i386
 
 
 >Description:
 	Setting SO_SNDLOWAT to 0 on a TCP socket and sending to a non-
 	local host (reachable with some delay and/or with limited bandwidth)
 	will cause the sending machine to go into busy-wait inside the kernel.
 
 	What appears to happen is this:
 
 	 o select() will always return that the socket is writable, even when
 	   sbspace() returns 0 due to the >= comparison in the sowritable()
 	   macro.
 
 	 o once the user writes, it appears that sosend() will loop internally
 	   since sbspace() is 0, no data will be added to the outgoing buffer,
 	   and the residue for each turn of the loop stays the same.  The test
 	   for the low-water mark does not kick in, so sbwait() will not be
 	   called.
 
 	It can clearly be argued that the program setting SO_SNDLOWAT to 0
 	is buggy, but the robustness against this mis-setting should be better
 	to prevent denial-of-service attacks by local users.
 
 >How-To-Repeat:
 	Run the attached program towards a non-local host reachable via
 	a "thin" line or over some delay by calling it:
 
 	% tstlowat low-water-mark number-of-buffers ip-address
 
 	and trying low-water-mark of 0.
 
 --- snip, snip --
 #include <stdio.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
 main(int argc, char *argv[])
 {
 	struct sockaddr_in sin;
 	int i, n, s, sndlowat;
 	char buf[65536];
 
 	sndlowat = atoi(argv[1]);
 	n = atoi(argv[2]);
 
 	if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
 		perror("socket"); exit(1);
 	}
 	if (setsockopt(s, SOL_SOCKET, SO_SNDLOWAT, (char *)&sndlowat,
 		       sizeof sndlowat) < 0) {
 		perror("setsockopt"); exit(1);
 	}
 	sin.sin_port = htons(9);	/* Discard port */
 	sin.sin_family = AF_INET;
 	if (inet_aton(argv[3], &sin.sin_addr) == 0) {
 		fprintf(stderr, "inet_aton"); exit(1);
 	}
 	if (connect(s, (struct sockaddr *)&sin, sizeof sin) < 0) {
 		perror("connect"); exit(1);
 	}
 
 	for (i=0; i<n; i++) {
 		if (write(s, buf, sizeof buf) < 0) {
 			perror("write"); exit(1);
 		}
 	}
 }
 --- snip, snip ---
 
 >Fix:
 	Sorry, I don't know.
 
 	Does a socket low-water mark of 0 really make sense?
 	If not, return EINVAL or something like that on an attempt at
 	setting it to 0?



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199706221420.HAA03342>