Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/tcp_input.c
Show All 12 Lines | |||||
tp->osd); | tp->osd); | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* CC wrapper hook functions | * CC wrapper hook functions | ||||
*/ | */ | ||||
void | void | ||||
cc_ack_received(struct tcpcb *tp, struct tcphdr *th, uint16_t type) | cc_ack_received(struct tcpcb *tp, struct tcphdr *th, uint16_t nsegs, | ||||
uint16_t type) | |||||
{ | { | ||||
INP_WLOCK_ASSERT(tp->t_inpcb); | INP_WLOCK_ASSERT(tp->t_inpcb); | ||||
tp->ccv->nsegs = nsegs; | |||||
tp->ccv->bytes_this_ack = BYTES_THIS_ACK(tp, th); | tp->ccv->bytes_this_ack = BYTES_THIS_ACK(tp, th); | ||||
if (tp->snd_cwnd <= tp->snd_wnd) | if (tp->snd_cwnd <= tp->snd_wnd) | ||||
tp->ccv->flags |= CCF_CWND_LIMITED; | tp->ccv->flags |= CCF_CWND_LIMITED; | ||||
else | else | ||||
tp->ccv->flags &= ~CCF_CWND_LIMITED; | tp->ccv->flags &= ~CCF_CWND_LIMITED; | ||||
if (type == CC_ACK) { | if (type == CC_ACK) { | ||||
if (tp->snd_cwnd > tp->snd_ssthresh) { | if (tp->snd_cwnd > tp->snd_ssthresh) { | ||||
tp->t_bytes_acked += min(tp->ccv->bytes_this_ack, | tp->t_bytes_acked += min(tp->ccv->bytes_this_ack, | ||||
V_tcp_abc_l_var * tcp_maxseg(tp)); | nsegs * V_tcp_abc_l_var * tcp_maxseg(tp)); | ||||
if (tp->t_bytes_acked >= tp->snd_cwnd) { | if (tp->t_bytes_acked >= tp->snd_cwnd) { | ||||
tp->t_bytes_acked -= tp->snd_cwnd; | tp->t_bytes_acked -= tp->snd_cwnd; | ||||
tp->ccv->flags |= CCF_ABC_SENTAWND; | tp->ccv->flags |= CCF_ABC_SENTAWND; | ||||
} | } | ||||
} else { | } else { | ||||
tp->ccv->flags &= ~CCF_ABC_SENTAWND; | tp->ccv->flags &= ~CCF_ABC_SENTAWND; | ||||
tp->t_bytes_acked = 0; | tp->t_bytes_acked = 0; | ||||
} | } | ||||
Show All 24 Lines | |||||
void | void | ||||
tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, | tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, | ||||
struct tcpcb *tp, int drop_hdrlen, int tlen, uint8_t iptos, | struct tcpcb *tp, int drop_hdrlen, int tlen, uint8_t iptos, | ||||
int ti_locked) | int ti_locked) | ||||
{ | { | ||||
int thflags, acked, ourfinisacked, needoutput = 0, sack_changed; | int thflags, acked, ourfinisacked, needoutput = 0, sack_changed; | ||||
int rstreason, todrop, win; | int rstreason, todrop, win; | ||||
u_long tiwin; | u_long tiwin; | ||||
uint16_t nsegs; | |||||
char *s; | char *s; | ||||
struct in_conninfo *inc; | struct in_conninfo *inc; | ||||
struct mbuf *mfree; | struct mbuf *mfree; | ||||
struct tcpopt to; | struct tcpopt to; | ||||
int tfo_syn; | int tfo_syn; | ||||
#ifdef TCPDEBUG | #ifdef TCPDEBUG | ||||
/* | /* | ||||
* The size of tcp_saveipgen must be the size of the max ip header, | * The size of tcp_saveipgen must be the size of the max ip header, | ||||
* now IPv6. | * now IPv6. | ||||
*/ | */ | ||||
u_char tcp_saveipgen[IP6_HDR_LEN]; | u_char tcp_saveipgen[IP6_HDR_LEN]; | ||||
struct tcphdr tcp_savetcp; | struct tcphdr tcp_savetcp; | ||||
short ostate = 0; | short ostate = 0; | ||||
#endif | #endif | ||||
thflags = th->th_flags; | thflags = th->th_flags; | ||||
inc = &tp->t_inpcb->inp_inc; | inc = &tp->t_inpcb->inp_inc; | ||||
tp->sackhint.last_sack_ack = 0; | tp->sackhint.last_sack_ack = 0; | ||||
sack_changed = 0; | sack_changed = 0; | ||||
nsegs = max(1, m->m_pkthdr.lro_nsegs); | |||||
/* | /* | ||||
* If this is either a state-changing packet or current state isn't | * If this is either a state-changing packet or current state isn't | ||||
* established, we require a write lock on tcbinfo. Otherwise, we | * established, we require a write lock on tcbinfo. Otherwise, we | ||||
* allow the tcbinfo to be in either alocked or unlocked, as the | * allow the tcbinfo to be in either alocked or unlocked, as the | ||||
* caller may have unnecessarily acquired a write lock due to a race. | * caller may have unnecessarily acquired a write lock due to a race. | ||||
*/ | */ | ||||
if ((thflags & (TH_SYN | TH_FIN | TH_RST)) != 0 || | if ((thflags & (TH_SYN | TH_FIN | TH_RST)) != 0 || | ||||
Show All 24 Lines | |||||
tcp_xmit_timer(tp, | tcp_xmit_timer(tp, | ||||
ticks - tp->t_rtttime); | ticks - tp->t_rtttime); | ||||
} | } | ||||
acked = BYTES_THIS_ACK(tp, th); | acked = BYTES_THIS_ACK(tp, th); | ||||
/* Run HHOOK_TCP_ESTABLISHED_IN helper hooks. */ | /* Run HHOOK_TCP_ESTABLISHED_IN helper hooks. */ | ||||
hhook_run_tcp_est_in(tp, th, &to); | hhook_run_tcp_est_in(tp, th, &to); | ||||
TCPSTAT_INC(tcps_rcvackpack); | TCPSTAT_ADD(tcps_rcvackpack, nsegs); | ||||
TCPSTAT_ADD(tcps_rcvackbyte, acked); | TCPSTAT_ADD(tcps_rcvackbyte, acked); | ||||
sbdrop(&so->so_snd, acked); | sbdrop(&so->so_snd, acked); | ||||
if (SEQ_GT(tp->snd_una, tp->snd_recover) && | if (SEQ_GT(tp->snd_una, tp->snd_recover) && | ||||
SEQ_LEQ(th->th_ack, tp->snd_recover)) | SEQ_LEQ(th->th_ack, tp->snd_recover)) | ||||
tp->snd_recover = th->th_ack - 1; | tp->snd_recover = th->th_ack - 1; | ||||
/* | /* | ||||
* Let the congestion control algorithm update | * Let the congestion control algorithm update | ||||
* congestion control related information. This | * congestion control related information. This | ||||
* typically means increasing the congestion | * typically means increasing the congestion | ||||
* window. | * window. | ||||
*/ | */ | ||||
cc_ack_received(tp, th, CC_ACK); | cc_ack_received(tp, th, nsegs, CC_ACK); | ||||
tp->snd_una = th->th_ack; | tp->snd_una = th->th_ack; | ||||
/* | /* | ||||
* Pull snd_wl2 up to prevent seq wrap relative | * Pull snd_wl2 up to prevent seq wrap relative | ||||
* to th_ack. | * to th_ack. | ||||
*/ | */ | ||||
tp->snd_wl2 = th->th_ack; | tp->snd_wl2 = th->th_ack; | ||||
tp->t_dupacks = 0; | tp->t_dupacks = 0; | ||||
Show All 24 Lines | |||||
* th_seq. | * th_seq. | ||||
*/ | */ | ||||
tp->snd_wl1 = th->th_seq; | tp->snd_wl1 = th->th_seq; | ||||
/* | /* | ||||
* Pull rcv_up up to prevent seq wrap relative to | * Pull rcv_up up to prevent seq wrap relative to | ||||
* rcv_nxt. | * rcv_nxt. | ||||
*/ | */ | ||||
tp->rcv_up = tp->rcv_nxt; | tp->rcv_up = tp->rcv_nxt; | ||||
TCPSTAT_INC(tcps_rcvpack); | TCPSTAT_ADD(tcps_rcvpack, nsegs); | ||||
TCPSTAT_ADD(tcps_rcvbyte, tlen); | TCPSTAT_ADD(tcps_rcvbyte, tlen); | ||||
#ifdef TCPDEBUG | #ifdef TCPDEBUG | ||||
if (so->so_options & SO_DEBUG) | if (so->so_options & SO_DEBUG) | ||||
tcp_trace(TA_INPUT, ostate, tp, | tcp_trace(TA_INPUT, ostate, tp, | ||||
(void *)tcp_saveipgen, &tcp_savetcp, 0); | (void *)tcp_saveipgen, &tcp_savetcp, 0); | ||||
#endif | #endif | ||||
TCP_PROBE3(debug__input, tp, th, mtod(m, const char *)); | TCP_PROBE3(debug__input, tp, th, mtod(m, const char *)); | ||||
Show All 24 Lines | |||||
if (th->th_ack != tp->snd_una || | if (th->th_ack != tp->snd_una || | ||||
((tp->t_flags & TF_SACK_PERMIT) && | ((tp->t_flags & TF_SACK_PERMIT) && | ||||
!sack_changed)) | !sack_changed)) | ||||
break; | break; | ||||
else if (!tcp_timer_active(tp, TT_REXMT)) | else if (!tcp_timer_active(tp, TT_REXMT)) | ||||
tp->t_dupacks = 0; | tp->t_dupacks = 0; | ||||
else if (++tp->t_dupacks > tcprexmtthresh || | else if (++tp->t_dupacks > tcprexmtthresh || | ||||
IN_FASTRECOVERY(tp->t_flags)) { | IN_FASTRECOVERY(tp->t_flags)) { | ||||
cc_ack_received(tp, th, CC_DUPACK); | cc_ack_received(tp, th, nsegs, | ||||
CC_DUPACK); | |||||
if ((tp->t_flags & TF_SACK_PERMIT) && | if ((tp->t_flags & TF_SACK_PERMIT) && | ||||
IN_FASTRECOVERY(tp->t_flags)) { | IN_FASTRECOVERY(tp->t_flags)) { | ||||
int awnd; | int awnd; | ||||
/* | /* | ||||
* Compute the amount of data in flight first. | * Compute the amount of data in flight first. | ||||
* We can inject new data into the pipe iff | * We can inject new data into the pipe iff | ||||
* we have less than 1/2 the original window's | * we have less than 1/2 the original window's | ||||
Show All 24 Lines | |||||
if (SEQ_LEQ(th->th_ack, | if (SEQ_LEQ(th->th_ack, | ||||
tp->snd_recover)) { | tp->snd_recover)) { | ||||
tp->t_dupacks = 0; | tp->t_dupacks = 0; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
/* Congestion signal before ack. */ | /* Congestion signal before ack. */ | ||||
cc_cong_signal(tp, th, CC_NDUPACK); | cc_cong_signal(tp, th, CC_NDUPACK); | ||||
cc_ack_received(tp, th, CC_DUPACK); | cc_ack_received(tp, th, nsegs, | ||||
CC_DUPACK); | |||||
tcp_timer_activate(tp, TT_REXMT, 0); | tcp_timer_activate(tp, TT_REXMT, 0); | ||||
tp->t_rtttime = 0; | tp->t_rtttime = 0; | ||||
if (tp->t_flags & TF_SACK_PERMIT) { | if (tp->t_flags & TF_SACK_PERMIT) { | ||||
TCPSTAT_INC( | TCPSTAT_INC( | ||||
tcps_sack_recovery_episode); | tcps_sack_recovery_episode); | ||||
tp->sack_newdata = tp->snd_nxt; | tp->sack_newdata = tp->snd_nxt; | ||||
tp->snd_cwnd = maxseg; | tp->snd_cwnd = maxseg; | ||||
(void) tp->t_fb->tfb_tcp_output(tp); | (void) tp->t_fb->tfb_tcp_output(tp); | ||||
Show All 17 Lines | |||||
* ACKs. Each indicates a segment | * ACKs. Each indicates a segment | ||||
* leaving the network, creating room | * leaving the network, creating room | ||||
* for more. Make sure we can send a | * for more. Make sure we can send a | ||||
* packet on reception of each duplicate | * packet on reception of each duplicate | ||||
* ACK by increasing snd_cwnd by one | * ACK by increasing snd_cwnd by one | ||||
* segment. Restore the original | * segment. Restore the original | ||||
* snd_cwnd after packet transmission. | * snd_cwnd after packet transmission. | ||||
*/ | */ | ||||
cc_ack_received(tp, th, CC_DUPACK); | cc_ack_received(tp, th, nsegs, | ||||
CC_DUPACK); | |||||
u_long oldcwnd = tp->snd_cwnd; | u_long oldcwnd = tp->snd_cwnd; | ||||
tcp_seq oldsndmax = tp->snd_max; | tcp_seq oldsndmax = tp->snd_max; | ||||
u_int sent; | u_int sent; | ||||
int avail; | int avail; | ||||
KASSERT(tp->t_dupacks == 1 || | KASSERT(tp->t_dupacks == 1 || | ||||
tp->t_dupacks == 2, | tp->t_dupacks == 2, | ||||
("%s: dupacks not 1 or 2", | ("%s: dupacks not 1 or 2", | ||||
Show All 24 Lines | |||||
process_ACK: | process_ACK: | ||||
INP_WLOCK_ASSERT(tp->t_inpcb); | INP_WLOCK_ASSERT(tp->t_inpcb); | ||||
acked = BYTES_THIS_ACK(tp, th); | acked = BYTES_THIS_ACK(tp, th); | ||||
KASSERT(acked >= 0, ("%s: acked unexepectedly negative " | KASSERT(acked >= 0, ("%s: acked unexepectedly negative " | ||||
"(tp->snd_una=%u, th->th_ack=%u, tp=%p, m=%p)", __func__, | "(tp->snd_una=%u, th->th_ack=%u, tp=%p, m=%p)", __func__, | ||||
tp->snd_una, th->th_ack, tp, m)); | tp->snd_una, th->th_ack, tp, m)); | ||||
TCPSTAT_INC(tcps_rcvackpack); | TCPSTAT_ADD(tcps_rcvackpack, nsegs); | ||||
TCPSTAT_ADD(tcps_rcvackbyte, acked); | TCPSTAT_ADD(tcps_rcvackbyte, acked); | ||||
/* | /* | ||||
* If we just performed our first retransmit, and the ACK | * If we just performed our first retransmit, and the ACK | ||||
* arrives within our recovery window, then it was a mistake | * arrives within our recovery window, then it was a mistake | ||||
* to do the retransmit in the first place. Recover our | * to do the retransmit in the first place. Recover our | ||||
* original cwnd and ssthresh, and proceed to transmit where | * original cwnd and ssthresh, and proceed to transmit where | ||||
* we left off. | * we left off. | ||||
Show All 24 Lines | |||||
if (acked == 0) | if (acked == 0) | ||||
goto step6; | goto step6; | ||||
/* | /* | ||||
* Let the congestion control algorithm update congestion | * Let the congestion control algorithm update congestion | ||||
* control related information. This typically means increasing | * control related information. This typically means increasing | ||||
* the congestion window. | * the congestion window. | ||||
*/ | */ | ||||
cc_ack_received(tp, th, CC_ACK); | cc_ack_received(tp, th, nsegs, CC_ACK); | ||||
SOCKBUF_LOCK(&so->so_snd); | SOCKBUF_LOCK(&so->so_snd); | ||||
if (acked > sbavail(&so->so_snd)) { | if (acked > sbavail(&so->so_snd)) { | ||||
if (tp->snd_wnd >= sbavail(&so->so_snd)) | if (tp->snd_wnd >= sbavail(&so->so_snd)) | ||||
tp->snd_wnd -= sbavail(&so->so_snd); | tp->snd_wnd -= sbavail(&so->so_snd); | ||||
else | else | ||||
tp->snd_wnd = 0; | tp->snd_wnd = 0; | ||||
mfree = sbcut_locked(&so->so_snd, | mfree = sbcut_locked(&so->so_snd, | ||||
Show All 12 Lines |