diff --git a/sys/net/route.h b/sys/net/route.h index c9c5c3f593ca..c5642a4153e7 100644 --- a/sys/net/route.h +++ b/sys/net/route.h @@ -139,7 +139,7 @@ struct ortentry { #define RTF_DYNAMIC 0x10 /* created dynamically (by redirect) */ #define RTF_MODIFIED 0x20 /* modified dynamically (by redirect) */ #define RTF_DONE 0x40 /* message confirmed */ -/* 0x80 unused */ +#define RTF_DELCLONE 0x80 /* delete cloned route */ #define RTF_CLONING 0x100 /* generate new routes on use */ #define RTF_XRESOLVE 0x200 /* external daemon resolves name */ #define RTF_LLINFO 0x400 /* generated by link layer (e.g. ARP) */ diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index b8b8278486ec..3204aa8f805e 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -531,6 +531,7 @@ in_pcbdetach(inp) { struct socket *so = inp->inp_socket; struct inpcbinfo *ipi = inp->inp_pcbinfo; + struct rtentry *rt = inp->inp_route.ro_rt; #ifdef IPSEC ipsec4_delete_pcbpolicy(inp); @@ -541,8 +542,28 @@ in_pcbdetach(inp) sofree(so); if (inp->inp_options) (void)m_free(inp->inp_options); - if (inp->inp_route.ro_rt) - rtfree(inp->inp_route.ro_rt); + if (rt) { + /* + * route deletion requires reference count to be <= zero + */ + if ((rt->rt_flags & RTF_DELCLONE) && + (rt->rt_flags & RTF_WASCLONED)) { + if (--rt->rt_refcnt <= 0) { + rt->rt_flags &= ~RTF_UP; + rtrequest(RTM_DELETE, rt_key(rt), + rt->rt_gateway, rt_mask(rt), + rt->rt_flags, (struct rtentry **)0); + } + else + /* + * more than one reference, bump it up + * again. + */ + rt->rt_refcnt++; + } + else + rtfree(rt); + } ip_freemoptions(inp->inp_moptions); inp->inp_vflag = 0; zfreei(ipi->ipi_zone, inp); diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 427e6c739445..f49a7f429d26 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -121,6 +121,11 @@ SYSCTL_INT(_net_inet_tcp, OID_AUTO, delayed_ack, CTLFLAG_RW, &tcp_delack_enabled, 0, "Delay ACK to try and piggyback it onto a data packet"); +int tcp_lq_overflow = 1; +SYSCTL_INT(_net_inet_tcp, OID_AUTO, tcp_lq_overflow, CTLFLAG_RW, + &tcp_lq_overflow, 0, + "Listen Queue Overflow"); + #ifdef TCP_DROP_SYNFIN static int drop_synfin = 0; SYSCTL_INT(_net_inet_tcp, OID_AUTO, drop_synfin, CTLFLAG_RW, @@ -710,6 +715,9 @@ tcp_input(m, off0, proto) tcpstat.tcps_listendrop++; so2 = sodropablereq(so); if (so2) { + if (tcp_lq_overflow) + sototcpcb(so2)->t_flags |= + TF_LQ_OVERFLOW; tcp_drop(sototcpcb(so2), ETIMEDOUT); so2 = sonewconn(so, 0); } diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c index 427e6c739445..f49a7f429d26 100644 --- a/sys/netinet/tcp_reass.c +++ b/sys/netinet/tcp_reass.c @@ -121,6 +121,11 @@ SYSCTL_INT(_net_inet_tcp, OID_AUTO, delayed_ack, CTLFLAG_RW, &tcp_delack_enabled, 0, "Delay ACK to try and piggyback it onto a data packet"); +int tcp_lq_overflow = 1; +SYSCTL_INT(_net_inet_tcp, OID_AUTO, tcp_lq_overflow, CTLFLAG_RW, + &tcp_lq_overflow, 0, + "Listen Queue Overflow"); + #ifdef TCP_DROP_SYNFIN static int drop_synfin = 0; SYSCTL_INT(_net_inet_tcp, OID_AUTO, drop_synfin, CTLFLAG_RW, @@ -710,6 +715,9 @@ tcp_input(m, off0, proto) tcpstat.tcps_listendrop++; so2 = sodropablereq(so); if (so2) { + if (tcp_lq_overflow) + sototcpcb(so2)->t_flags |= + TF_LQ_OVERFLOW; tcp_drop(sototcpcb(so2), ETIMEDOUT); so2 = sonewconn(so, 0); } diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index 68f87aa173b5..da613d569c01 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -680,6 +680,18 @@ tcp_close(tp) tcpstat.tcps_cachedssthresh++; } } + rt = inp->inp_route.ro_rt; + if (rt) { + /* + * mark route for deletion if no information is + * cached. + */ + if ((tp->t_flags & TF_LQ_OVERFLOW) && + ((rt->rt_rmx.rmx_locks & RTV_RTT) == 0)){ + if (rt->rt_rmx.rmx_rtt == 0) + rt->rt_flags |= RTF_DELCLONE; + } + } no_valid_rt: /* free the reassembly queue, if any */ while((q = LIST_FIRST(&tp->t_segq)) != NULL) { diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c index 68f87aa173b5..da613d569c01 100644 --- a/sys/netinet/tcp_timewait.c +++ b/sys/netinet/tcp_timewait.c @@ -680,6 +680,18 @@ tcp_close(tp) tcpstat.tcps_cachedssthresh++; } } + rt = inp->inp_route.ro_rt; + if (rt) { + /* + * mark route for deletion if no information is + * cached. + */ + if ((tp->t_flags & TF_LQ_OVERFLOW) && + ((rt->rt_rmx.rmx_locks & RTV_RTT) == 0)){ + if (rt->rt_rmx.rmx_rtt == 0) + rt->rt_flags |= RTF_DELCLONE; + } + } no_valid_rt: /* free the reassembly queue, if any */ while((q = LIST_FIRST(&tp->t_segq)) != NULL) { diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h index eb2c9b14edc6..af18c091c40d 100644 --- a/sys/netinet/tcp_var.h +++ b/sys/netinet/tcp_var.h @@ -94,6 +94,7 @@ struct tcpcb { #define TF_RCVD_CC 0x04000 /* a CC was received in SYN */ #define TF_SENDCCNEW 0x08000 /* send CCnew instead of CC in SYN */ #define TF_MORETOCOME 0x10000 /* More data to be appended to sock */ +#define TF_LQ_OVERFLOW 0x20000 /* listen queue overflow */ int t_force; /* 1 if forcing out a byte */ tcp_seq snd_una; /* send unacknowledged */