- Add a new function tcp_twrecycleable, which tells us if the ISN which

we will generate for a given ip/port tuple has advanced far enough
for the time_wait socket in question to be safely recycled.

- Have in_pcblookup_local use tcp_twrecycleable to determine if
time_Wait sockets which are hogging local ports can be safely
freed.

This change preserves proper TIME_WAIT behavior under normal
circumstances while allowing for safe and fast recycling whenever
ephemeral port space is scarce.
This commit is contained in:
Mike Silbersack 2003-11-01 07:30:08 +00:00
parent ac8711d28e
commit 96af9ea52b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=121850
4 changed files with 52 additions and 0 deletions

View File

@ -950,6 +950,7 @@ in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay)
* First see if this local port is in use by looking on the
* port hash list.
*/
retrylookup:
porthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(lport,
pcbinfo->porthashmask)];
LIST_FOREACH(phd, porthash, phd_hash) {
@ -967,6 +968,17 @@ in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay)
if ((inp->inp_vflag & INP_IPV4) == 0)
continue;
#endif
/*
* Clean out old time_wait sockets if they
* are clogging up needed local ports.
*/
if ((inp->inp_vflag & INP_TIMEWAIT) != 0) {
if (tcp_twrecycleable((struct tcptw *)inp->inp_ppcb)) {
tcp_twclose((struct tcptw *)inp->inp_ppcb, 0);
match = NULL;
goto retrylookup;
}
}
if (inp->inp_faddr.s_addr != INADDR_ANY)
wildcard++;
if (inp->inp_laddr.s_addr != INADDR_ANY) {

View File

@ -1637,6 +1637,7 @@ tcp_twstart(tp)
tw->snd_nxt = tp->snd_nxt;
tw->rcv_nxt = tp->rcv_nxt;
tw->iss = tp->iss;
tw->cc_recv = tp->cc_recv;
tw->cc_send = tp->cc_send;
tw->t_starttime = tp->t_starttime;
@ -1671,6 +1672,24 @@ tcp_twstart(tp)
INP_UNLOCK(inp);
}
/*
* Determine if the ISN we will generate has advanced beyond the last
* sequence number used by the previous connection. If so, indicate
* that it is safe to recycle this tw socket by returning 1.
*/
int
tcp_twrecycleable(struct tcptw *tw)
{
tcp_seq new_isn = tw->iss;
new_isn += (ticks - tw->t_starttime) * (ISN_BYTES_PER_SECOND / hz);
if (SEQ_GT(new_isn, tw->snd_nxt))
return 1;
else
return 0;
}
struct tcptw *
tcp_twclose(struct tcptw *tw, int reuse)
{

View File

@ -1637,6 +1637,7 @@ tcp_twstart(tp)
tw->snd_nxt = tp->snd_nxt;
tw->rcv_nxt = tp->rcv_nxt;
tw->iss = tp->iss;
tw->cc_recv = tp->cc_recv;
tw->cc_send = tp->cc_send;
tw->t_starttime = tp->t_starttime;
@ -1671,6 +1672,24 @@ tcp_twstart(tp)
INP_UNLOCK(inp);
}
/*
* Determine if the ISN we will generate has advanced beyond the last
* sequence number used by the previous connection. If so, indicate
* that it is safe to recycle this tw socket by returning 1.
*/
int
tcp_twrecycleable(struct tcptw *tw)
{
tcp_seq new_isn = tw->iss;
new_isn += (ticks - tw->t_starttime) * (ISN_BYTES_PER_SECOND / hz);
if (SEQ_GT(new_isn, tw->snd_nxt))
return 1;
else
return 0;
}
struct tcptw *
tcp_twclose(struct tcptw *tw, int reuse)
{

View File

@ -246,6 +246,7 @@ struct tcptw {
struct inpcb *tw_inpcb; /* XXX back pointer to internet pcb */
tcp_seq snd_nxt;
tcp_seq rcv_nxt;
tcp_seq iss;
tcp_cc cc_recv;
tcp_cc cc_send;
u_short last_win; /* cached window value */
@ -471,6 +472,7 @@ void tcp_canceltimers(struct tcpcb *);
struct tcpcb *
tcp_close(struct tcpcb *);
void tcp_twstart(struct tcpcb *);
int tcp_twrecycleable(struct tcptw *tw);
struct tcptw *
tcp_twclose(struct tcptw *_tw, int _reuse);
void tcp_ctlinput(int, struct sockaddr *, void *);