[Midnightbsd-cvs] src [7191] trunk/sys/netinet: TCP Resassemly resource exhaustion bug:

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Tue Jul 28 20:30:13 EDT 2015


Revision: 7191
          http://svnweb.midnightbsd.org/src/?rev=7191
Author:   laffer1
Date:     2015-07-28 20:30:12 -0400 (Tue, 28 Jul 2015)
Log Message:
-----------
TCP Resassemly resource exhaustion bug:

There is a mistake with the introduction of VNET, which converted the
global limit on the number of segments that could belong to reassembly
queues into a per-VNET limit.  Because mbufs are allocated from a
global pool, in the presence of a sufficient number of VNETs, the
total number of mbufs attached to reassembly queues can grow to the
total number of mbufs in the system, at which point all network
traffic would cease.

Obtained from: FreeBSD 8

Modified Paths:
--------------
    trunk/sys/netinet/tcp_reass.c
    trunk/sys/netinet/tcp_subr.c
    trunk/sys/netinet/tcp_var.h

Modified: trunk/sys/netinet/tcp_reass.c
===================================================================
--- trunk/sys/netinet/tcp_reass.c	2015-07-28 11:57:01 UTC (rev 7190)
+++ trunk/sys/netinet/tcp_reass.c	2015-07-29 00:30:12 UTC (rev 7191)
@@ -80,29 +80,25 @@
 SYSCTL_NODE(_net_inet_tcp, OID_AUTO, reass, CTLFLAG_RW, 0,
     "TCP Segment Reassembly Queue");
 
-static VNET_DEFINE(int, tcp_reass_maxseg) = 0;
-#define	V_tcp_reass_maxseg		VNET(tcp_reass_maxseg)
+static int tcp_reass_maxseg = 0;
 SYSCTL_VNET_PROC(_net_inet_tcp_reass, OID_AUTO, maxsegments,
     CTLTYPE_INT | CTLFLAG_RDTUN,
-    &VNET_NAME(tcp_reass_maxseg), 0, &tcp_reass_sysctl_maxseg, "I",
+    &tcp_reass_maxseg, 0, &tcp_reass_sysctl_maxseg, "I",
     "Global maximum number of TCP Segments in Reassembly Queue");
 
-static VNET_DEFINE(int, tcp_reass_qsize) = 0;
-#define	V_tcp_reass_qsize		VNET(tcp_reass_qsize)
-SYSCTL_VNET_PROC(_net_inet_tcp_reass, OID_AUTO, cursegments,
+static int tcp_reass_qsize = 0;
+SYSCTL_PROC(_net_inet_tcp_reass, OID_AUTO, cursegments,
     CTLTYPE_INT | CTLFLAG_RD,
-    &VNET_NAME(tcp_reass_qsize), 0, &tcp_reass_sysctl_qsize, "I",
+    &tcp_reass_qsize, 0, &tcp_reass_sysctl_qsize, "I",
     "Global number of TCP Segments currently in Reassembly Queue");
 
-static VNET_DEFINE(int, tcp_reass_overflows) = 0;
-#define	V_tcp_reass_overflows		VNET(tcp_reass_overflows)
-SYSCTL_VNET_INT(_net_inet_tcp_reass, OID_AUTO, overflows,
+static int tcp_reass_overflows = 0;
+SYSCTL_INT(_net_inet_tcp_reass, OID_AUTO, overflows,
     CTLTYPE_INT | CTLFLAG_RD,
-    &VNET_NAME(tcp_reass_overflows), 0,
+    &tcp_reass_overflows, 0,
     "Global number of TCP Segment Reassembly Queue Overflows");
 
-static VNET_DEFINE(uma_zone_t, tcp_reass_zone);
-#define	V_tcp_reass_zone		VNET(tcp_reass_zone)
+static uma_zone_t tcp_reass_zone;
 
 /* Initialize TCP reassembly queue */
 static void
@@ -109,34 +105,25 @@
 tcp_reass_zone_change(void *tag)
 {
 
-	V_tcp_reass_maxseg = nmbclusters / 16;
-	uma_zone_set_max(V_tcp_reass_zone, V_tcp_reass_maxseg);
+	tcp_reass_maxseg = nmbclusters / 16;
+	uma_zone_set_max(tcp_reass_zone, tcp_reass_maxseg);
 }
 
 void
-tcp_reass_init(void)
+tcp_reass_global_init(void)
 {
 
-	V_tcp_reass_maxseg = nmbclusters / 16;
+	tcp_reass_maxseg = nmbclusters / 16;
 	TUNABLE_INT_FETCH("net.inet.tcp.reass.maxsegments",
-	    &V_tcp_reass_maxseg);
-	V_tcp_reass_zone = uma_zcreate("tcpreass", sizeof (struct tseg_qent),
+	    &tcp_reass_maxseg);
+	tcp_reass_zone = uma_zcreate("tcpreass", sizeof (struct tseg_qent),
 	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
-	uma_zone_set_max(V_tcp_reass_zone, V_tcp_reass_maxseg);
+	uma_zone_set_max(tcp_reass_zone, tcp_reass_maxseg);
 	EVENTHANDLER_REGISTER(nmbclusters_change,
 	    tcp_reass_zone_change, NULL, EVENTHANDLER_PRI_ANY);
 }
 
-#ifdef VIMAGE
 void
-tcp_reass_destroy(void)
-{
-
-	uma_zdestroy(V_tcp_reass_zone);
-}
-#endif
-
-void
 tcp_reass_flush(struct tcpcb *tp)
 {
 	struct tseg_qent *qe;
@@ -146,7 +133,7 @@
 	while ((qe = LIST_FIRST(&tp->t_segq)) != NULL) {
 		LIST_REMOVE(qe, tqe_q);
 		m_freem(qe->tqe_m);
-		uma_zfree(V_tcp_reass_zone, qe);
+		uma_zfree(tcp_reass_zone, qe);
 		tp->t_segqlen--;
 	}
 
@@ -158,7 +145,7 @@
 static int
 tcp_reass_sysctl_maxseg(SYSCTL_HANDLER_ARGS)
 {
-	V_tcp_reass_maxseg = uma_zone_get_max(V_tcp_reass_zone);
+	tcp_reass_maxseg = uma_zone_get_max(tcp_reass_zone);
 	return (sysctl_handle_int(oidp, arg1, arg2, req));
 }
 
@@ -165,7 +152,7 @@
 static int
 tcp_reass_sysctl_qsize(SYSCTL_HANDLER_ARGS)
 {
-	V_tcp_reass_qsize = uma_zone_get_cur(V_tcp_reass_zone);
+	tcp_reass_qsize = uma_zone_get_cur(tcp_reass_zone);
 	return (sysctl_handle_int(oidp, arg1, arg2, req));
 }
 
@@ -213,7 +200,7 @@
 	 */
 	if ((th->th_seq != tp->rcv_nxt || !TCPS_HAVEESTABLISHED(tp->t_state)) &&
 	    tp->t_segqlen >= (so->so_rcv.sb_hiwat / tp->t_maxseg) + 1) {
-		V_tcp_reass_overflows++;
+		tcp_reass_overflows++;
 		TCPSTAT_INC(tcps_rcvmemdrop);
 		m_freem(m);
 		*tlenp = 0;
@@ -232,7 +219,7 @@
 	 * Use a temporary structure on the stack for the missing segment
 	 * when the zone is exhausted. Otherwise we may get stuck.
 	 */
-	te = uma_zalloc(V_tcp_reass_zone, M_NOWAIT);
+	te = uma_zalloc(tcp_reass_zone, M_NOWAIT);
 	if (te == NULL) {
 		if (th->th_seq != tp->rcv_nxt || !TCPS_HAVEESTABLISHED(tp->t_state)) {
 			TCPSTAT_INC(tcps_rcvmemdrop);
@@ -283,7 +270,7 @@
 				TCPSTAT_ADD(tcps_rcvdupbyte, *tlenp);
 				m_freem(m);
 				if (te != &tqs)
-					uma_zfree(V_tcp_reass_zone, te);
+					uma_zfree(tcp_reass_zone, te);
 				tp->t_segqlen--;
 				/*
 				 * Try to present any queued data
@@ -320,7 +307,7 @@
 		nq = LIST_NEXT(q, tqe_q);
 		LIST_REMOVE(q, tqe_q);
 		m_freem(q->tqe_m);
-		uma_zfree(V_tcp_reass_zone, q);
+		uma_zfree(tcp_reass_zone, q);
 		tp->t_segqlen--;
 		q = nq;
 	}
@@ -359,7 +346,7 @@
 		else
 			sbappendstream_locked(&so->so_rcv, q->tqe_m);
 		if (q != &tqs)
-			uma_zfree(V_tcp_reass_zone, q);
+			uma_zfree(tcp_reass_zone, q);
 		tp->t_segqlen--;
 		q = nq;
 	} while (q && q->tqe_th->th_seq == tp->rcv_nxt);

Modified: trunk/sys/netinet/tcp_subr.c
===================================================================
--- trunk/sys/netinet/tcp_subr.c	2015-07-28 11:57:01 UTC (rev 7190)
+++ trunk/sys/netinet/tcp_subr.c	2015-07-29 00:30:12 UTC (rev 7191)
@@ -312,7 +312,6 @@
 	tcp_tw_init();
 	syncache_init();
 	tcp_hc_init();
-	tcp_reass_init();
 
 	TUNABLE_INT_FETCH("net.inet.tcp.sack.enable", &V_tcp_do_sack);
 	V_sack_hole_zone = uma_zcreate("sackhole", sizeof(struct sackhole),
@@ -322,6 +321,8 @@
 	if (!IS_DEFAULT_VNET(curvnet))
 		return;
 
+	tcp_reass_global_init();
+
 	/* XXX virtualize those bellow? */
 	tcp_delacktime = TCPTV_DELACK;
 	tcp_keepinit = TCPTV_KEEP_INIT;
@@ -369,7 +370,6 @@
 tcp_destroy(void)
 {
 
-	tcp_reass_destroy();
 	tcp_hc_destroy();
 	syncache_destroy();
 	tcp_tw_destroy();

Modified: trunk/sys/netinet/tcp_var.h
===================================================================
--- trunk/sys/netinet/tcp_var.h	2015-07-28 11:57:01 UTC (rev 7190)
+++ trunk/sys/netinet/tcp_var.h	2015-07-29 00:30:12 UTC (rev 7191)
@@ -667,11 +667,8 @@
 char	*tcp_log_vain(struct in_conninfo *, struct tcphdr *, void *,
 	    const void *);
 int	 tcp_reass(struct tcpcb *, struct tcphdr *, int *, struct mbuf *);
-void	 tcp_reass_init(void);
+void	 tcp_reass_global_init(void);
 void	 tcp_reass_flush(struct tcpcb *);
-#ifdef VIMAGE
-void	 tcp_reass_destroy(void);
-#endif
 void	 tcp_input(struct mbuf *, int);
 u_long	 tcp_maxmtu(struct in_conninfo *, int *);
 u_long	 tcp_maxmtu6(struct in_conninfo *, int *);



More information about the Midnightbsd-cvs mailing list