Skip site navigation (1)Skip section navigation (2)
Date:      22 Jun 1997 13:36:54 +0000 (GMT)
From:      sthaug@nethelp.no
To:        FreeBSD-gnats-submit@FreeBSD.ORG
Cc:        sthaug@nethelp.no
Subject:   kern/3925: SO_SNDLOWAT of 0 causes kernel to use 99% of CPU time on TCP send
Message-ID:  <19970622133654.29391.qmail@verdi.nethelp.no>
Resent-Message-ID: <199706221340.GAA02000@hub.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         3925
>Category:       kern
>Synopsis:       SO_SNDLOWAT of 0 causes kernel to use 99% of CPU time on TCP send
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sun Jun 22 06:40:01 PDT 1997
>Last-Modified:
>Originator:     Steinar Haug
>Organization:
Nethelp Consulting
>Release:        FreeBSD 2.2-961014-SNAP i386
>Environment:

This may be a generic 4.4BSD networking bug. It applies to NetBSD-1.2, FreeBSD
(all versions I've checked, eg. 2.2-BETA, 3.0-970124-SNAP). It was discovered
because BIND-8.1.1-T2B named sets SO_SNDLOWAT to 0 if SO_SNDLOWAT is defined.

>Description:

Setting SO_SNDLOWAT to 0 and then sending data with TCP to a site which is more
than a few milliseconds away (eg. connected over a 28.800 link) causes the kernel
to use 99% of the CPU time, as reported by vmstat or top. Using a SO_SNDLOWAT > 0
makes the problem disappear.

It's quite possible that this effect *always* occurs, but it's much more visible
against a slow site.

>How-To-Repeat:

Compile the following program, which sends a number of buffers to the discard
port at a given address. Run the program with

% tstlowat 0 50 ip-address

ie. send 50 buffers to a given address with SO_SNDLOWAT set to 0. Observe with
vmstat how the kernel uses all of the CPU.

#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);
		}
	}
}


>Fix:
	
Sorry, no known fix. Easy workaround is to use a SO_SNDLOWAT which is > 0.

>Audit-Trail:
>Unformatted:



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