summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/netinet/tcp_input.c7
-rw-r--r--sys/netinet/tcp_reass.c7
-rw-r--r--sys/netinet/tcp_subr.c39
-rw-r--r--sys/netinet/tcp_timer.c83
-rw-r--r--sys/netinet/tcp_timer.h8
-rw-r--r--sys/netinet/tcp_timewait.c39
-rw-r--r--sys/netinet/tcp_var.h6
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 *
OpenPOWER on IntegriCloud