Remove a panic(); if the zone allocator can't provide more timewait

structures, reuse the oldest one.  Also move the expiry timer from
a per-structure callout to the tcp slow timer.

Sponsored by: DARPA, NAI Labs
This commit is contained in:
Jonathan Lemon 2003-03-08 22:06:20 +00:00
parent 921f8bb982
commit 607b0b0cc9
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=112009
7 changed files with 118 additions and 75 deletions

View File

@ -2862,7 +2862,7 @@ tcp_timewait(tw, to, th, m, tlen)
if ((ticks - tw->t_starttime) > tcp_msl)
goto reset;
if (CC_GT(to->to_cc, tw->cc_recv)) {
tcp_twclose(tw);
(void) tcp_twclose(tw, 0);
return (1);
}
goto drop;
@ -2892,7 +2892,7 @@ tcp_timewait(tw, to, th, m, tlen)
* are above the previous ones.
*/
if ((thflags & TH_SYN) && SEQ_GT(th->th_seq, tw->rcv_nxt)) {
tcp_twclose(tw);
(void) tcp_twclose(tw, 0);
return (1);
}
@ -2908,8 +2908,7 @@ tcp_timewait(tw, to, th, m, tlen)
if (thflags & TH_FIN) {
seq = th->th_seq + tlen + (thflags & TH_SYN ? 1 : 0);
if (seq + 1 == tw->rcv_nxt)
callout_reset(tw->tt_2msl,
2 * tcp_msl, tcp_timer_2msl_tw, tw);
tcp_timer_2msl_reset(tw, 2 * tcp_msl);
}
/*

View File

@ -2862,7 +2862,7 @@ tcp_timewait(tw, to, th, m, tlen)
if ((ticks - tw->t_starttime) > tcp_msl)
goto reset;
if (CC_GT(to->to_cc, tw->cc_recv)) {
tcp_twclose(tw);
(void) tcp_twclose(tw, 0);
return (1);
}
goto drop;
@ -2892,7 +2892,7 @@ tcp_timewait(tw, to, th, m, tlen)
* are above the previous ones.
*/
if ((thflags & TH_SYN) && SEQ_GT(th->th_seq, tw->rcv_nxt)) {
tcp_twclose(tw);
(void) tcp_twclose(tw, 0);
return (1);
}
@ -2908,8 +2908,7 @@ tcp_timewait(tw, to, th, m, tlen)
if (thflags & TH_FIN) {
seq = th->th_seq + tlen + (thflags & TH_SYN ? 1 : 0);
if (seq + 1 == tw->rcv_nxt)
callout_reset(tw->tt_2msl,
2 * tcp_msl, tcp_timer_2msl_tw, tw);
tcp_timer_2msl_reset(tw, 2 * tcp_msl);
}
/*

View File

@ -202,10 +202,6 @@ struct tcpcb_mem {
struct callout tcpcb_mem_rexmt, tcpcb_mem_persist, tcpcb_mem_keep;
struct callout tcpcb_mem_2msl, tcpcb_mem_delack;
};
struct tcptw_mem {
struct tcptw tw;
struct callout tcptw_mem_2msl;
};
static uma_zone_t tcpcb_zone;
static uma_zone_t tcptw_zone;
@ -261,10 +257,10 @@ tcp_init()
tcpcb_zone = uma_zcreate("tcpcb", sizeof(struct tcpcb_mem),
NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
uma_zone_set_max(tcpcb_zone, maxsockets);
tcptw_zone = uma_zcreate("tcptw", sizeof(struct tcptw_mem),
tcptw_zone = uma_zcreate("tcptw", sizeof(struct tcptw),
NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
uma_zone_set_max(tcptw_zone, maxsockets);
tcp_timer_init();
syncache_init();
}
@ -1599,18 +1595,19 @@ void
tcp_twstart(tp)
struct tcpcb *tp;
{
struct tcptw_mem *tm;
struct tcptw *tw;
struct inpcb *inp;
int tw_time, acknow;
struct socket *so;
tm = uma_zalloc(tcptw_zone, M_NOWAIT);
if (tm == NULL)
/* EEEK! -- preserve old structure or just kill everything? */
/* must obtain tcbinfo lock in order to drop the structure. */
panic("uma_zalloc(tcptw)");
tw = &tm->tw;
tw = uma_zalloc(tcptw_zone, M_NOWAIT);
if (tw == NULL) {
tw = tcp_timer_2msl_tw(1);
if (tw == NULL) {
tcp_close(tp);
return;
}
}
inp = tp->t_inpcb;
tw->tw_inpcb = inp;
@ -1633,7 +1630,7 @@ tcp_twstart(tp)
tw->cc_recv = tp->cc_recv;
tw->cc_send = tp->cc_send;
tw->t_starttime = tp->t_starttime;
callout_init(tw->tt_2msl = &tm->tcptw_mem_2msl, 0);
tw->tw_time = 0;
/* XXX
* If this code will
@ -1658,23 +1655,21 @@ tcp_twstart(tp)
inp->inp_socket = NULL;
inp->inp_ppcb = (caddr_t)tw;
inp->inp_vflag |= INP_TIMEWAIT;
callout_reset(tw->tt_2msl, tw_time, tcp_timer_2msl_tw, tw);
tcp_timer_2msl_reset(tw, tw_time);
if (acknow)
tcp_twrespond(tw, TH_ACK);
INP_UNLOCK(inp);
}
void
tcp_twclose(tw)
struct tcptw *tw;
struct tcptw *
tcp_twclose(struct tcptw *tw, int reuse)
{
struct inpcb *inp;
inp = tw->tw_inpcb;
tw->tw_inpcb = NULL;
callout_stop(tw->tt_2msl);
tcp_timer_2msl_stop(tw);
inp->inp_ppcb = NULL;
uma_zfree(tcptw_zone, tw);
#ifdef INET6
if (inp->inp_vflag & INP_IPV6PROTO)
in6_pcbdetach(inp);
@ -1682,6 +1677,10 @@ tcp_twclose(tw)
#endif
in_pcbdetach(inp);
tcpstat.tcps_closed++;
if (reuse)
return (tw);
uma_zfree(tcptw_zone, tw);
return (NULL);
}
int

View File

@ -136,10 +136,11 @@ tcp_slowtimo()
int s;
s = splnet();
tcp_maxidle = tcp_keepcnt * tcp_keepintvl;
splx(s);
INP_INFO_WLOCK(&tcbinfo);
(void) tcp_timer_2msl_tw(0);
INP_INFO_WUNLOCK(&tcbinfo);
}
/*
@ -251,31 +252,69 @@ tcp_timer_2msl(xtp)
splx(s);
}
void
tcp_timer_2msl_tw(xtw)
void *xtw;
{
struct tcptw *tw = xtw;
int s;
struct twlist {
LIST_HEAD(, tcptw) tw_list;
struct tcptw tw_tail;
};
#define TWLIST_NLISTS 2
static struct twlist twl_2msl[TWLIST_NLISTS];
static struct twlist *tw_2msl_list[] = { &twl_2msl[0], &twl_2msl[1], NULL };
s = splnet();
INP_INFO_WLOCK(&tcbinfo);
if (tw->tw_inpcb == NULL) {
INP_INFO_WUNLOCK(&tcbinfo);
splx(s);
return;
void
tcp_timer_init(void)
{
int i;
struct twlist *twl;
for (i = 0; i < TWLIST_NLISTS; i++) {
twl = &twl_2msl[i];
LIST_INIT(&twl->tw_list);
LIST_INSERT_HEAD(&twl->tw_list, &twl->tw_tail, tw_2msl);
}
INP_LOCK(tw->tw_inpcb);
if (callout_pending(tw->tt_2msl) || !callout_active(tw->tt_2msl)) {
INP_UNLOCK(tw->tw_inpcb);
INP_INFO_WUNLOCK(&tcbinfo);
splx(s);
return;
}
void
tcp_timer_2msl_reset(struct tcptw *tw, int timeo)
{
int i;
struct tcptw *tw_tail;
if (tw->tw_time != 0)
LIST_REMOVE(tw, tw_2msl);
tw->tw_time = timeo + ticks;
i = timeo > tcp_msl ? 1 : 0;
tw_tail = &twl_2msl[i].tw_tail;
LIST_INSERT_BEFORE(tw_tail, tw, tw_2msl);
}
void
tcp_timer_2msl_stop(struct tcptw *tw)
{
if (tw->tw_time != 0)
LIST_REMOVE(tw, tw_2msl);
}
struct tcptw *
tcp_timer_2msl_tw(int reuse)
{
struct tcptw *tw, *tw_tail;
struct twlist *twl;
int i;
for (i = 0; i < 2; i++) {
twl = tw_2msl_list[i];
tw_tail = &twl->tw_tail;
for (;;) {
tw = LIST_FIRST(&twl->tw_list);
if (tw == tw_tail || (!reuse && tw->tw_time > ticks))
break;
INP_LOCK(tw->tw_inpcb);
if (tcp_twclose(tw, reuse) != NULL)
return (tw);
}
}
callout_deactivate(tw->tt_2msl);
tcp_twclose(tw);
INP_INFO_WUNLOCK(&tcbinfo);
splx(s);
return (NULL);
}
void

View File

@ -151,8 +151,14 @@ extern int tcp_msl;
extern int tcp_ttl; /* time to live for TCP segs */
extern int tcp_backoff[];
struct tcptw;
void tcp_timer_init(void);
void tcp_timer_2msl(void *xtp);
void tcp_timer_2msl_tw(void *xtw); /* XXX temporary */
struct tcptw *
tcp_timer_2msl_tw(int _reuse); /* XXX temporary */
void tcp_timer_2msl_reset(struct tcptw *_tw, int _timeo);
void tcp_timer_2msl_stop(struct tcptw *_tw);
void tcp_timer_keep(void *xtp);
void tcp_timer_persist(void *xtp);
void tcp_timer_rexmt(void *xtp);

View File

@ -202,10 +202,6 @@ struct tcpcb_mem {
struct callout tcpcb_mem_rexmt, tcpcb_mem_persist, tcpcb_mem_keep;
struct callout tcpcb_mem_2msl, tcpcb_mem_delack;
};
struct tcptw_mem {
struct tcptw tw;
struct callout tcptw_mem_2msl;
};
static uma_zone_t tcpcb_zone;
static uma_zone_t tcptw_zone;
@ -261,10 +257,10 @@ tcp_init()
tcpcb_zone = uma_zcreate("tcpcb", sizeof(struct tcpcb_mem),
NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
uma_zone_set_max(tcpcb_zone, maxsockets);
tcptw_zone = uma_zcreate("tcptw", sizeof(struct tcptw_mem),
tcptw_zone = uma_zcreate("tcptw", sizeof(struct tcptw),
NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
uma_zone_set_max(tcptw_zone, maxsockets);
tcp_timer_init();
syncache_init();
}
@ -1599,18 +1595,19 @@ void
tcp_twstart(tp)
struct tcpcb *tp;
{
struct tcptw_mem *tm;
struct tcptw *tw;
struct inpcb *inp;
int tw_time, acknow;
struct socket *so;
tm = uma_zalloc(tcptw_zone, M_NOWAIT);
if (tm == NULL)
/* EEEK! -- preserve old structure or just kill everything? */
/* must obtain tcbinfo lock in order to drop the structure. */
panic("uma_zalloc(tcptw)");
tw = &tm->tw;
tw = uma_zalloc(tcptw_zone, M_NOWAIT);
if (tw == NULL) {
tw = tcp_timer_2msl_tw(1);
if (tw == NULL) {
tcp_close(tp);
return;
}
}
inp = tp->t_inpcb;
tw->tw_inpcb = inp;
@ -1633,7 +1630,7 @@ tcp_twstart(tp)
tw->cc_recv = tp->cc_recv;
tw->cc_send = tp->cc_send;
tw->t_starttime = tp->t_starttime;
callout_init(tw->tt_2msl = &tm->tcptw_mem_2msl, 0);
tw->tw_time = 0;
/* XXX
* If this code will
@ -1658,23 +1655,21 @@ tcp_twstart(tp)
inp->inp_socket = NULL;
inp->inp_ppcb = (caddr_t)tw;
inp->inp_vflag |= INP_TIMEWAIT;
callout_reset(tw->tt_2msl, tw_time, tcp_timer_2msl_tw, tw);
tcp_timer_2msl_reset(tw, tw_time);
if (acknow)
tcp_twrespond(tw, TH_ACK);
INP_UNLOCK(inp);
}
void
tcp_twclose(tw)
struct tcptw *tw;
struct tcptw *
tcp_twclose(struct tcptw *tw, int reuse)
{
struct inpcb *inp;
inp = tw->tw_inpcb;
tw->tw_inpcb = NULL;
callout_stop(tw->tt_2msl);
tcp_timer_2msl_stop(tw);
inp->inp_ppcb = NULL;
uma_zfree(tcptw_zone, tw);
#ifdef INET6
if (inp->inp_vflag & INP_IPV6PROTO)
in6_pcbdetach(inp);
@ -1682,6 +1677,10 @@ tcp_twclose(tw)
#endif
in_pcbdetach(inp);
tcpstat.tcps_closed++;
if (reuse)
return (tw);
uma_zfree(tcptw_zone, tw);
return (NULL);
}
int

View File

@ -247,7 +247,8 @@ struct tcptw {
struct ucred *tw_cred; /* user credentials */
u_long t_recent;
u_long t_starttime;
struct callout *tt_2msl; /* 2*msl TIME_WAIT timer */
int tw_time;
LIST_ENTRY(tcptw) tw_2msl;
};
/*
@ -464,7 +465,8 @@ void tcp_canceltimers(struct tcpcb *);
struct tcpcb *
tcp_close(struct tcpcb *);
void tcp_twstart(struct tcpcb *);
void tcp_twclose(struct tcptw *);
struct tcptw *
tcp_twclose(struct tcptw *_tw, int _reuse);
void tcp_ctlinput(int, struct sockaddr *, void *);
int tcp_ctloutput(struct socket *, struct sockopt *);
struct tcpcb *