Index: sys/netinet/tcp_input.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/tcp_input.c,v retrieving revision 1.205 retrieving revision 1.205.2.1 diff -c -r1.205 -r1.205.2.1 *** sys/netinet/tcp_input.c 7 May 2003 05:26:27 -0000 1.205 --- sys/netinet/tcp_input.c 15 Mar 2004 20:02:07 -0000 1.205.2.1 *************** *** 57,62 **** --- 57,64 ---- #include /* before tcp_seq.h, for tcp_random18() */ + #include + #include #include *************** *** 97,104 **** #include - MALLOC_DEFINE(M_TSEGQ, "tseg_qent", "TCP segment queue entry"); - static const int tcprexmtthresh = 3; tcp_cc tcp_ccgen; --- 99,104 ---- *************** *** 134,139 **** --- 134,157 ---- &tcp_do_rfc3390, 0, "Enable RFC 3390 (Increasing TCP's Initial Congestion Window)"); + SYSCTL_NODE(_net_inet_tcp, OID_AUTO, reass, CTLFLAG_RW, 0, + "TCP Segment Reassembly Queue"); + + static 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; *************** *** 175,180 **** --- 193,211 ---- (tp->t_flags & TF_RXWIN0SENT) == 0) && \ (tcp_delack_enabled || (tp->t_flags & TF_NEEDSYN))) + /* Initialize TCP reassembly queue */ + uma_zone_t tcp_reass_zone; + void + tcp_reass_init() + { + tcp_reass_maxseg = nmbclusters / 16; + TUNABLE_INT_FETCH("net.inet.tcp.reass.maxsegments", + &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(tcp_reass_zone, tcp_reass_maxseg); + } + static int tcp_reass(tp, th, tlenp, m) register struct tcpcb *tp; *************** *** 185,191 **** struct tseg_qent *q; struct tseg_qent *p = NULL; struct tseg_qent *nq; ! struct tseg_qent *te; struct socket *so = tp->t_inpcb->inp_socket; int flags; --- 216,222 ---- struct tseg_qent *q; struct tseg_qent *p = NULL; struct tseg_qent *nq; ! struct tseg_qent *te = NULL; struct socket *so = tp->t_inpcb->inp_socket; int flags; *************** *** 196,209 **** if (th == 0) goto present; ! /* 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); if (te == NULL) { tcpstat.tcps_rcvmemdrop++; m_freem(m); return (0); } /* * Find a segment which begins after this one does. --- 227,258 ---- 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, or hit the zone limit ! * just drop the pkt. ! */ ! te = uma_zalloc(tcp_reass_zone, M_NOWAIT); if (te == NULL) { tcpstat.tcps_rcvmemdrop++; m_freem(m); return (0); } + tcp_reass_qsize++; /* * Find a segment which begins after this one does. *************** *** 228,234 **** tcpstat.tcps_rcvduppack++; tcpstat.tcps_rcvdupbyte += *tlenp; m_freem(m); ! FREE(te, M_TSEGQ); /* * Try to present any queued data * at the left window edge to the user. --- 277,284 ---- tcpstat.tcps_rcvduppack++; tcpstat.tcps_rcvdupbyte += *tlenp; m_freem(m); ! uma_zfree(tcp_reass_zone, te); ! tcp_reass_qsize--; /* * Try to present any queued data * at the left window edge to the user. *************** *** 263,269 **** nq = LIST_NEXT(q, tqe_q); LIST_REMOVE(q, tqe_q); m_freem(q->tqe_m); ! FREE(q, M_TSEGQ); q = nq; } --- 313,320 ---- nq = LIST_NEXT(q, tqe_q); LIST_REMOVE(q, tqe_q); m_freem(q->tqe_m); ! uma_zfree(tcp_reass_zone, q); ! tcp_reass_qsize--; q = nq; } *************** *** 297,303 **** m_freem(q->tqe_m); else sbappend(&so->so_rcv, q->tqe_m); ! FREE(q, M_TSEGQ); q = nq; } while (q && q->tqe_th->th_seq == tp->rcv_nxt); ND6_HINT(tp); --- 348,355 ---- m_freem(q->tqe_m); else sbappend(&so->so_rcv, q->tqe_m); ! uma_zfree(tcp_reass_zone, q); ! tcp_reass_qsize--; q = nq; } while (q && q->tqe_th->th_seq == tp->rcv_nxt); ND6_HINT(tp); Index: sys/netinet/tcp_subr.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/tcp_subr.c,v retrieving revision 1.160 retrieving revision 1.160.2.1 diff -c -r1.160 -r1.160.2.1 *** sys/netinet/tcp_subr.c 7 May 2003 05:26:27 -0000 1.160 --- sys/netinet/tcp_subr.c 15 Mar 2004 20:02:07 -0000 1.160.2.1 *************** *** 262,267 **** --- 262,268 ---- uma_zone_set_max(tcptw_zone, maxsockets); tcp_timer_init(); syncache_init(); + tcp_reass_init(); } /* *************** *** 763,769 **** while ((q = LIST_FIRST(&tp->t_segq)) != NULL) { LIST_REMOVE(q, tqe_q); m_freem(q->tqe_m); ! FREE(q, M_TSEGQ); } inp->inp_ppcb = NULL; tp->t_inpcb = NULL; --- 764,771 ---- while ((q = LIST_FIRST(&tp->t_segq)) != NULL) { LIST_REMOVE(q, tqe_q); m_freem(q->tqe_m); ! uma_zfree(tcp_reass_zone, q); ! tcp_reass_qsize--; } inp->inp_ppcb = NULL; tp->t_inpcb = NULL; *************** *** 824,830 **** != NULL) { LIST_REMOVE(te, tqe_q); m_freem(te->tqe_m); ! FREE(te, M_TSEGQ); } } INP_UNLOCK(inpb); --- 826,833 ---- != NULL) { LIST_REMOVE(te, tqe_q); m_freem(te->tqe_m); ! uma_zfree(tcp_reass_zone, te); ! tcp_reass_qsize--; } } INP_UNLOCK(inpb); Index: sys/netinet/tcp_var.h =================================================================== RCS file: /home/ncvs/src/sys/netinet/tcp_var.h,v retrieving revision 1.89 retrieving revision 1.89.2.1 diff -c -r1.89 -r1.89.2.1 *** sys/netinet/tcp_var.h 7 May 2003 05:26:27 -0000 1.89 --- sys/netinet/tcp_var.h 15 Mar 2004 20:02:07 -0000 1.89.2.1 *************** *** 54,62 **** struct mbuf *tqe_m; /* mbuf contains packet */ }; LIST_HEAD(tsegqe_head, tseg_qent); ! #ifdef MALLOC_DECLARE ! MALLOC_DECLARE(M_TSEGQ); ! #endif struct tcptemp { u_char tt_ipgen[40]; /* the size must be of max ip header, now IPv6 */ --- 54,61 ---- struct mbuf *tqe_m; /* mbuf contains packet */ }; LIST_HEAD(tsegqe_head, tseg_qent); ! extern int tcp_reass_qsize; ! extern struct uma_zone *tcp_reass_zone; struct tcptemp { u_char tt_ipgen[40]; /* the size must be of max ip header, now IPv6 */ *************** *** 489,494 **** --- 488,494 ---- int tcp_output(struct tcpcb *); struct inpcb * tcp_quench(struct inpcb *, int); + void tcp_reass_init(void); void tcp_respond(struct tcpcb *, void *, struct tcphdr *, struct mbuf *, tcp_seq, tcp_seq, int); int tcp_twrespond(struct tcptw *, struct socket *, struct mbuf *, int);