svn commit: r359923 - in head: lib/libc/sys sys/kern sys/sys

Jonathan T. Looney jtl at FreeBSD.org
Tue Apr 14 15:38:19 UTC 2020


Author: jtl
Date: Tue Apr 14 15:38:18 2020
New Revision: 359923
URL: https://svnweb.freebsd.org/changeset/base/359923

Log:
  Make sonewconn() overflow messages have per-socket rate-limits and values.
  
  sonewconn() emits debug-level messages when a listen socket's queue
  overflows. Currently, sonewconn() tracks overflows on a global basis. It
  will only log one message every 60 seconds, regardless of how many sockets
  experience overflows. And, when it next logs at the end of the 60 seconds,
  it records a single message referencing a single PCB with the total number
  of overflows across all sockets.
  
  This commit changes to per-socket overflow tracking. The code will now
  log one message every 60 seconds per socket. And, the code will provide
  per-socket queue length and overflow counts. It also provides a way to
  change the period between log messages using a sysctl.
  
  Reviewed by:	jhb (previous version), bcr (manpages)
  MFC after:	2 weeks
  Sponsored by:	Netflix, Inc.
  Differential Revision:	https://reviews.freebsd.org/D24316

Modified:
  head/lib/libc/sys/listen.2
  head/sys/kern/uipc_socket.c
  head/sys/sys/socketvar.h

Modified: head/lib/libc/sys/listen.2
==============================================================================
--- head/lib/libc/sys/listen.2	Tue Apr 14 15:30:34 2020	(r359922)
+++ head/lib/libc/sys/listen.2	Tue Apr 14 15:38:18 2020	(r359923)
@@ -28,7 +28,7 @@
 .\"	From: @(#)listen.2	8.2 (Berkeley) 12/11/93
 .\" $FreeBSD$
 .\"
-.Dd August 18, 2016
+.Dd April 14, 2020
 .Dt LISTEN 2
 .Os
 .Sh NAME
@@ -110,6 +110,13 @@ or less than zero is specified,
 .Fa backlog
 is silently forced to
 .Va kern.ipc.soacceptqueue .
+.Pp
+If the listen queue overflows, the kernel will emit a LOG_DEBUG syslog message.
+The
+.Xr sysctl 3
+MIB variable
+.Va kern.ipc.sooverinterval
+specifies a per-socket limit on how often the kernel will emit these messages.
 .Sh INTERACTION WITH ACCEPT FILTERS
 When accept filtering is used on a socket, a second queue will
 be used to hold sockets that have connected, but have not yet

Modified: head/sys/kern/uipc_socket.c
==============================================================================
--- head/sys/kern/uipc_socket.c	Tue Apr 14 15:30:34 2020	(r359922)
+++ head/sys/kern/uipc_socket.c	Tue Apr 14 15:38:18 2020	(r359923)
@@ -575,6 +575,11 @@ SYSCTL_INT(_regression, OID_AUTO, sonewconn_earlytest,
     &regression_sonewconn_earlytest, 0, "Perform early sonewconn limit test");
 #endif
 
+static struct timeval overinterval = { 60, 0 };
+SYSCTL_TIMEVAL_SEC(_kern_ipc, OID_AUTO, sooverinterval, CTLFLAG_RW,
+    &overinterval,
+    "Delay in seconds between warnings for listen socket overflows");
+
 /*
  * When an attempt at a new connection is noted on a socket which accepts
  * connections, sonewconn is called.  If the connection is possible (subject
@@ -587,14 +592,10 @@ SYSCTL_INT(_regression, OID_AUTO, sonewconn_earlytest,
 struct socket *
 sonewconn(struct socket *head, int connstatus)
 {
-	static struct timeval lastover;
-	static struct timeval overinterval = { 60, 0 };
-	static int overcount;
-
 	struct sbuf descrsb;
 	struct socket *so;
-	u_int over;
-	int len;
+	int len, overcount;
+	u_int qlen;
 	const char localprefix[] = "local:";
 	char descrbuf[SUNPATHLEN + sizeof(localprefix)];
 #if defined(INET6)
@@ -602,18 +603,31 @@ sonewconn(struct socket *head, int connstatus)
 #elif defined(INET)
 	char addrbuf[INET_ADDRSTRLEN];
 #endif
+	bool dolog, over;
 
 	SOLISTEN_LOCK(head);
 	over = (head->sol_qlen > 3 * head->sol_qlimit / 2);
-	SOLISTEN_UNLOCK(head);
 #ifdef REGRESSION
 	if (regression_sonewconn_earlytest && over) {
 #else
 	if (over) {
 #endif
-		overcount++;
+		head->sol_overcount++;
+		dolog = !!ratecheck(&head->sol_lastover, &overinterval);
 
-		if (ratecheck(&lastover, &overinterval)) {
+		/*
+		 * If we're going to log, copy the overflow count and queue
+		 * length from the listen socket before dropping the lock.
+		 * Also, reset the overflow count.
+		 */
+		if (dolog) {
+			overcount = head->sol_overcount;
+			head->sol_overcount = 0;
+			qlen = head->sol_qlen;
+		}
+		SOLISTEN_UNLOCK(head);
+
+		if (dolog) {
 			/*
 			 * Try to print something descriptive about the
 			 * socket for the error message.
@@ -686,7 +700,7 @@ sonewconn(struct socket *head, int connstatus)
 			    "%i already in queue awaiting acceptance "
 			    "(%d occurrences)\n",
 			    __func__, head->so_pcb, sbuf_data(&descrsb),
-			    head->sol_qlen, overcount);
+			    qlen, overcount);
 			sbuf_delete(&descrsb);
 
 			overcount = 0;
@@ -694,6 +708,7 @@ sonewconn(struct socket *head, int connstatus)
 
 		return (NULL);
 	}
+	SOLISTEN_UNLOCK(head);
 	VNET_ASSERT(head->so_vnet != NULL, ("%s: so %p vnet is NULL",
 	    __func__, head));
 	so = soalloc(head->so_vnet);

Modified: head/sys/sys/socketvar.h
==============================================================================
--- head/sys/sys/socketvar.h	Tue Apr 14 15:30:34 2020	(r359922)
+++ head/sys/sys/socketvar.h	Tue Apr 14 15:38:18 2020	(r359923)
@@ -172,6 +172,10 @@ struct socket {
 			short		sol_sbsnd_flags;
 			sbintime_t	sol_sbrcv_timeo;
 			sbintime_t	sol_sbsnd_timeo;
+
+			/* Information tracking listen queue overflows. */
+			struct timeval	sol_lastover;	/* (e) */
+			int		sol_overcount;	/* (e) */
 		};
 	};
 };


More information about the svn-src-head mailing list