diff options
author | jlemon <jlemon@FreeBSD.org> | 2003-03-08 22:06:20 +0000 |
---|---|---|
committer | jlemon <jlemon@FreeBSD.org> | 2003-03-08 22:06:20 +0000 |
commit | 03b8ace4891ef0ac6e1d27e79b9464022ed5fba0 (patch) | |
tree | 86b7ff103cc19bffc08502fceb82fff6fc3c8d83 | |
parent | 3cab7a88ab3bf9db32f46801047c9350030d5e77 (diff) | |
download | FreeBSD-src-03b8ace4891ef0ac6e1d27e79b9464022ed5fba0.zip FreeBSD-src-03b8ace4891ef0ac6e1d27e79b9464022ed5fba0.tar.gz |
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
-rw-r--r-- | sys/netinet/tcp_input.c | 7 | ||||
-rw-r--r-- | sys/netinet/tcp_reass.c | 7 | ||||
-rw-r--r-- | sys/netinet/tcp_subr.c | 39 | ||||
-rw-r--r-- | sys/netinet/tcp_timer.c | 83 | ||||
-rw-r--r-- | sys/netinet/tcp_timer.h | 8 | ||||
-rw-r--r-- | sys/netinet/tcp_timewait.c | 39 | ||||
-rw-r--r-- | sys/netinet/tcp_var.h | 6 |
7 files changed, 116 insertions, 73 deletions
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 7b4827a..7717e06 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -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); } /* diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c index 7b4827a..7717e06 100644 --- a/sys/netinet/tcp_reass.c +++ b/sys/netinet/tcp_reass.c @@ -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); } /* diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index f4d05ab..e96647f 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -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 diff --git a/sys/netinet/tcp_timer.c b/sys/netinet/tcp_timer.c index 16955d6..98a3546 100644 --- a/sys/netinet/tcp_timer.c +++ b/sys/netinet/tcp_timer.c @@ -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); } +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 }; + void -tcp_timer_2msl_tw(xtw) - void *xtw; +tcp_timer_init(void) { - struct tcptw *tw = xtw; - int s; + int i; + struct twlist *twl; - s = splnet(); - INP_INFO_WLOCK(&tcbinfo); - if (tw->tw_inpcb == NULL) { - INP_INFO_WUNLOCK(&tcbinfo); - splx(s); - return; + 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 diff --git a/sys/netinet/tcp_timer.h b/sys/netinet/tcp_timer.h index 40080b7..9b62b6f 100644 --- a/sys/netinet/tcp_timer.h +++ b/sys/netinet/tcp_timer.h @@ -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); diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c index f4d05ab..e96647f 100644 --- a/sys/netinet/tcp_timewait.c +++ b/sys/netinet/tcp_timewait.c @@ -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 diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h index e4a07f8..18780d7 100644 --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -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 * |