summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacques Vidrine <nectar@FreeBSD.org>2004-03-17 10:50:46 +0000
committerJacques Vidrine <nectar@FreeBSD.org>2004-03-17 10:50:46 +0000
commitf65ff4e7c66d67e7c43a7725a468e3e2f57554d6 (patch)
treeacd9d43ecfdb0d23e9fd0e2428e3ca215f682cb7
parent3a8a551a3591f41b50724b5af1d0d7bfea023cff (diff)
downloadsrc-test2-f65ff4e7c66d67e7c43a7725a468e3e2f57554d6.tar.gz
src-test2-f65ff4e7c66d67e7c43a7725a468e3e2f57554d6.zip
MFC in part tcp_input.c 1.228, tcp_subr.c 1.182, tcp_var.h 1.98:
Limit TCP segment reassembly queue size.
Notes
Notes: svn path=/releng/4.7/; revision=127109
-rw-r--r--UPDATING3
-rw-r--r--sys/conf/newvers.sh2
-rw-r--r--sys/netinet/tcp_input.c37
-rw-r--r--sys/netinet/tcp_subr.c7
-rw-r--r--sys/netinet/tcp_var.h2
5 files changed, 50 insertions, 1 deletions
diff --git a/UPDATING b/UPDATING
index 7c8b4cf8eeb8..389e172aaf81 100644
--- a/UPDATING
+++ b/UPDATING
@@ -17,6 +17,9 @@ minimal number of processes, if possible, for that patch. For those
updates that don't have an advisory, or to be safe, you can do a full
build and install as described in the COMMON ITEMS section.
+20040317: p26 FreeBSD-SA-04:04.tcp
+ Limit TCP segment reassembly queue size.
+
20040205: p25 FreeBSD-SA-04:02.shmat
Correct a reference counting bug in shmat(2).
diff --git a/sys/conf/newvers.sh b/sys/conf/newvers.sh
index 33bf46869467..bee2ec75bb1a 100644
--- a/sys/conf/newvers.sh
+++ b/sys/conf/newvers.sh
@@ -36,7 +36,7 @@
TYPE="FreeBSD"
REVISION="4.7"
-BRANCH="RELEASE-p25"
+BRANCH="RELEASE-p26"
RELEASE="${REVISION}-${BRANCH}"
VERSION="${TYPE} ${RELEASE}"
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 5ae1d9370ccb..94d2a5b27710 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -126,6 +126,24 @@ SYSCTL_INT(_net_inet_tcp, OID_AUTO, drop_synfin, CTLFLAG_RW,
&drop_synfin, 0, "Drop TCP packets with SYN+FIN set");
#endif
+SYSCTL_NODE(_net_inet_tcp, OID_AUTO, reass, CTLFLAG_RW, 0,
+ "TCP Segment Reassembly Queue");
+
+int tcp_reass_maxseg = 0;
+SYSCTL_INT(_net_inet_tcp_reass, OID_AUTO, maxsegments, CTLFLAG_RD,
+ &tcp_reass_maxseg, 0,
+ "Global maximum number of TCP Segments in Reassembly Queue");
+
+int tcp_reass_qsize = 0;
+SYSCTL_INT(_net_inet_tcp_reass, OID_AUTO, cursegments, CTLFLAG_RD,
+ &tcp_reass_qsize, 0,
+ "Global number of TCP Segments currently in Reassembly Queue");
+
+static int tcp_reass_overflows = 0;
+SYSCTL_INT(_net_inet_tcp_reass, OID_AUTO, overflows, CTLFLAG_RD,
+ &tcp_reass_overflows, 0,
+ "Global number of TCP Segment Reassembly Queue Overflows");
+
struct inpcbhead tcb;
#define tcb6 tcb /* for KAME src sync over BSD*'s */
struct inpcbinfo tcbinfo;
@@ -183,6 +201,21 @@ tcp_reass(tp, th, tlenp, m)
if (th == 0)
goto present;
+ /*
+ * Limit the number of segments in the reassembly queue to prevent
+ * holding on to too many segments (and thus running out of mbufs).
+ * Make sure to let the missing segment through which caused this
+ * queue. Always keep one global queue entry spare to be able to
+ * process the missing segment.
+ */
+ if (th->th_seq != tp->rcv_nxt &&
+ tcp_reass_qsize + 1 >= tcp_reass_maxseg) {
+ tcp_reass_overflows++;
+ tcpstat.tcps_rcvmemdrop++;
+ m_freem(m);
+ return (0);
+ }
+
/* Allocate a new queue entry. If we can't, just drop the pkt. XXX */
MALLOC(te, struct tseg_qent *, sizeof (struct tseg_qent), M_TSEGQ,
M_NOWAIT);
@@ -191,6 +224,7 @@ tcp_reass(tp, th, tlenp, m)
m_freem(m);
return (0);
}
+ tcp_reass_qsize++;
/*
* Find a segment which begins after this one does.
@@ -216,6 +250,7 @@ tcp_reass(tp, th, tlenp, m)
tcpstat.tcps_rcvdupbyte += *tlenp;
m_freem(m);
free(te, M_TSEGQ);
+ tcp_reass_qsize--;
/*
* Try to present any queued data
* at the left window edge to the user.
@@ -251,6 +286,7 @@ tcp_reass(tp, th, tlenp, m)
LIST_REMOVE(q, tqe_q);
m_freem(q->tqe_m);
free(q, M_TSEGQ);
+ tcp_reass_qsize--;
q = nq;
}
@@ -285,6 +321,7 @@ present:
else
sbappend(&so->so_rcv, q->tqe_m);
free(q, M_TSEGQ);
+ tcp_reass_qsize--;
q = nq;
} while (q && q->tqe_th->th_seq == tp->rcv_nxt);
ND6_HINT(tp);
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index 7007e0e21c63..f6974bd6ee4d 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -233,6 +233,11 @@ tcp_init()
&tcbinfo.porthashmask);
tcbinfo.ipi_zone = zinit("tcpcb", sizeof(struct inp_tp), maxsockets,
ZONE_INTERRUPT, 0);
+
+ tcp_reass_maxseg = nmbclusters / 16;
+ TUNABLE_INT_FETCH("net.inet.tcp.reass.maxsegments",
+ &tcp_reass_maxseg);
+
#ifdef INET6
#define TCP_MINPROTOHDR (sizeof(struct ip6_hdr) + sizeof(struct tcphdr))
#else /* INET6 */
@@ -742,6 +747,7 @@ tcp_close(tp)
LIST_REMOVE(q, tqe_q);
m_freem(q->tqe_m);
FREE(q, M_TSEGQ);
+ tcp_reass_qsize--;
}
inp->inp_ppcb = NULL;
soisdisconnected(so);
@@ -779,6 +785,7 @@ tcp_drain()
LIST_REMOVE(te, tqe_q);
m_freem(te->tqe_m);
FREE(te, M_TSEGQ);
+ tcp_reass_qsize--;
}
}
}
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
index b1e36aa2a6b7..0a2260680bac 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -53,6 +53,8 @@ struct tseg_qent {
struct mbuf *tqe_m; /* mbuf contains packet */
};
LIST_HEAD(tsegqe_head, tseg_qent);
+extern int tcp_reass_maxseg;
+extern int tcp_reass_qsize;
#ifdef MALLOC_DECLARE
MALLOC_DECLARE(M_TSEGQ);
#endif