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:
parent
921f8bb982
commit
607b0b0cc9
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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 *
|
||||
|
Loading…
x
Reference in New Issue
Block a user