diff options
author | Jacques Vidrine <nectar@FreeBSD.org> | 2004-03-17 10:50:46 +0000 |
---|---|---|
committer | Jacques Vidrine <nectar@FreeBSD.org> | 2004-03-17 10:50:46 +0000 |
commit | f65ff4e7c66d67e7c43a7725a468e3e2f57554d6 (patch) | |
tree | acd9d43ecfdb0d23e9fd0e2428e3ca215f682cb7 | |
parent | 3a8a551a3591f41b50724b5af1d0d7bfea023cff (diff) | |
download | src-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-- | UPDATING | 3 | ||||
-rw-r--r-- | sys/conf/newvers.sh | 2 | ||||
-rw-r--r-- | sys/netinet/tcp_input.c | 37 | ||||
-rw-r--r-- | sys/netinet/tcp_subr.c | 7 | ||||
-rw-r--r-- | sys/netinet/tcp_var.h | 2 |
5 files changed, 50 insertions, 1 deletions
@@ -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 |