Mercurial > ecos
diff packages/net/bsd_tcpip/current/src/sys/netinet/tcp_input.c @ 3013:286a2ab55044
* src/sys/netinet/if_ether.c: Merge fix from FreeBSD CVS r1.108.
Prevents creation of reciprocal ARP cache entries for hosts not on
local subnet.
* cdl/freebsd_net.cdl:
* include/netinet/tcp_var.c:
* src/sys/netinet/tcp_subr.c:
* src/sys/netinet/tcp_input.c: Merge fix from FreeBSD CVS. Introduces
a maximum size for the TCP reassembly queue to limit network buffer
usage associated with reassembly. Enable CYGNUM_NET_TCP_REASS_DIVISOR
and set it to configure the maximum number of buffers usable for TCP
reassembly.
| author | jlarmour |
|---|---|
| date | Tue, 22 Feb 2011 04:36:20 +0000 |
| parents | 74dbf4c3f2e1 |
| children | 9c050c918d4a |
line wrap: on
line diff
--- a/packages/net/bsd_tcpip/current/src/sys/netinet/tcp_input.c +++ b/packages/net/bsd_tcpip/current/src/sys/netinet/tcp_input.c @@ -132,6 +132,26 @@ SYSCTL_INT(_net_inet_tcp, OID_AUTO, drop &drop_synfin, 0, "Drop TCP packets with SYN+FIN set"); #endif +#ifdef CYGNUM_NET_TCP_REASS_DIVISOR +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"); +#endif + struct inpcbhead tcb; #define tcb6 tcb /* for KAME src sync over BSD*'s */ struct inpcbinfo tcbinfo; @@ -185,6 +205,23 @@ 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. + */ +#ifdef CYGNUM_NET_TCP_REASS_DIVISOR + 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); + } +#endif + /* 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); @@ -193,6 +230,9 @@ tcp_reass(tp, th, tlenp, m) m_freem(m); return (0); } +#ifdef CYGNUM_NET_TCP_REASS_DIVISOR + tcp_reass_qsize++; +#endif /* * Find a segment which begins after this one does. @@ -218,6 +258,9 @@ tcp_reass(tp, th, tlenp, m) tcpstat.tcps_rcvdupbyte += *tlenp; m_freem(m); FREE(te, M_TSEGQ); +#ifdef CYGNUM_NET_TCP_REASS_DIVISOR + tcp_reass_qsize--; +#endif /* * Try to present any queued data * at the left window edge to the user. @@ -253,6 +296,9 @@ tcp_reass(tp, th, tlenp, m) LIST_REMOVE(q, tqe_q); m_freem(q->tqe_m); FREE(q, M_TSEGQ); +#ifdef CYGNUM_NET_TCP_REASS_DIVISOR + tcp_reass_qsize--; +#endif q = nq; } @@ -287,6 +333,9 @@ present: else sbappend(&so->so_rcv, q->tqe_m); FREE(q, M_TSEGQ); +#ifdef CYGNUM_NET_TCP_REASS_DIVISOR + tcp_reass_qsize--; +#endif q = nq; } while (q && q->tqe_th->th_seq == tp->rcv_nxt); ND6_HINT(tp);
