Changeset View
Standalone View
sys/netinet/tcp_output.c
Show First 20 Lines • Show All 204 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
int idle, sendalot, curticks; | int idle, sendalot, curticks; | ||||
int sack_rxmit, sack_bytes_rxmt; | int sack_rxmit, sack_bytes_rxmt; | ||||
struct sackhole *p; | struct sackhole *p; | ||||
int tso, mtu; | int tso, mtu; | ||||
struct tcpopt to; | struct tcpopt to; | ||||
unsigned int wanted_cookie = 0; | unsigned int wanted_cookie = 0; | ||||
unsigned int dont_sendalot = 0; | unsigned int dont_sendalot = 0; | ||||
#if 0 | #if 1 | ||||
int maxburst = TCP_MAXBURST; | int maxburst = TCP_MAXBURST; | ||||
#endif | #endif | ||||
#ifdef INET6 | #ifdef INET6 | ||||
struct ip6_hdr *ip6 = NULL; | struct ip6_hdr *ip6 = NULL; | ||||
int isipv6; | int isipv6; | ||||
isipv6 = (tp->t_inpcb->inp_vflag & INP_IPV6) != 0; | isipv6 = (tp->t_inpcb->inp_vflag & INP_IPV6) != 0; | ||||
#endif | #endif | ||||
Show All 28 Lines | if (idle && ticks - tp->t_rcvtime >= tp->t_rxtcur) | ||||
cc_after_idle(tp); | cc_after_idle(tp); | ||||
tp->t_flags &= ~TF_LASTIDLE; | tp->t_flags &= ~TF_LASTIDLE; | ||||
if (idle) { | if (idle) { | ||||
if (tp->t_flags & TF_MORETOCOME) { | if (tp->t_flags & TF_MORETOCOME) { | ||||
tp->t_flags |= TF_LASTIDLE; | tp->t_flags |= TF_LASTIDLE; | ||||
idle = 0; | idle = 0; | ||||
} | } | ||||
} | } | ||||
/* | |||||
* Compute a reasonable burst limit | |||||
*/ | |||||
maxburst = tp->snd_cwnd - | |||||
(abs((tp->snd_max - tp->snd_una) - (tp->snd_cwnd>>1)) / | |||||
(tp->snd_cwnd>>1)) * (tp->snd_cwnd>>1); | |||||
cc: Can you elaborate how this translates to max cwnd/2? Is that divide and then multiply (tp… | |||||
rscheffAuthorUnsubmitted Done Inline ActionsYes, you are correct - i couldn't translate my excel formula properly here. See below for the intended burst size relative to flightsize vs cwnd The idea here is, to set maxburst relative to flight_size, limiting the maximum burst to half cwnd, when flightsize(pipe) is also half cwnd (allowing for clients that ACK only twice per RTT), but smaller maximum bursts, when the pipe is nearly empty or nearly full - to prevent line-rate bursts of huge cwnd from occuring (as we have seen during cubic testing). The formula (relative to cwnd) here should be thus maxburst = (tp->snd_cwnd>>1) - abs( (tp->snd_max - tp->snd_una) - (tp->snd_cwnd>>1) ). The drawback compared to pacing is, that a full flight will not necessarily be re-established within one RTT, but a much more agressive ramp up to cwnd will happen over a few RTTs (potentially with bursts too large to get absorbed by network queue buffers) https://www.wolframalpha.com/input/?i=plot+y%3Dmax(0.1,0.5-abs(x-0.5))+from+x%3D0+to+1 rscheff: Yes, you are correct - i couldn't translate my excel formula properly here. See below for the… | |||||
maxburst = max(maxburst, tcp_compute_initwnd(tp->t_maxseg)) / | |||||
tp->t_maxseg; | |||||
again: | again: | ||||
/* | /* | ||||
* If we've recently taken a timeout, snd_max will be greater than | * If we've recently taken a timeout, snd_max will be greater than | ||||
* snd_nxt. There may be SACK information that allows us to avoid | * snd_nxt. There may be SACK information that allows us to avoid | ||||
* resending already delivered data. Adjust snd_nxt accordingly. | * resending already delivered data. Adjust snd_nxt accordingly. | ||||
*/ | */ | ||||
if ((tp->t_flags & TF_SACK_PERMIT) && | if ((tp->t_flags & TF_SACK_PERMIT) && | ||||
SEQ_LT(tp->snd_nxt, tp->snd_max)) | SEQ_LT(tp->snd_nxt, tp->snd_max)) | ||||
▲ Show 20 Lines • Show All 1,328 Lines • ▼ Show 20 Lines | timer: | ||||
* Any pending ACK has now been sent. | * Any pending ACK has now been sent. | ||||
*/ | */ | ||||
if (SEQ_GT(tp->rcv_nxt + recwin, tp->rcv_adv)) | if (SEQ_GT(tp->rcv_nxt + recwin, tp->rcv_adv)) | ||||
tp->rcv_adv = tp->rcv_nxt + recwin; | tp->rcv_adv = tp->rcv_nxt + recwin; | ||||
tp->last_ack_sent = tp->rcv_nxt; | tp->last_ack_sent = tp->rcv_nxt; | ||||
tp->t_flags &= ~(TF_ACKNOW | TF_DELACK); | tp->t_flags &= ~(TF_ACKNOW | TF_DELACK); | ||||
if (tcp_timer_active(tp, TT_DELACK)) | if (tcp_timer_active(tp, TT_DELACK)) | ||||
tcp_timer_activate(tp, TT_DELACK, 0); | tcp_timer_activate(tp, TT_DELACK, 0); | ||||
#if 0 | #if 1 | ||||
impUnsubmitted Not Done Inline Actionsone would think a symbolic constant here might be in order here. Also, the comment below seems stale... imp: one would think a symbolic constant here might be in order here.
Also, the comment below seems… | |||||
/* | /* | ||||
* This completely breaks TCP if newreno is turned on. What happens | * This completely breaks TCP if newreno is turned on. What happens | ||||
* is that if delayed-acks are turned on on the receiver, this code | * is that if delayed-acks are turned on on the receiver, this code | ||||
* on the transmitter effectively destroys the TCP window, forcing | * on the transmitter effectively destroys the TCP window, forcing | ||||
* it to four packets (1.5Kx4 = 6K window). | * it to four packets (1.5Kx4 = 6K window). | ||||
*/ | */ | ||||
if (sendalot && --maxburst) | if (sendalot && --maxburst) | ||||
goto again; | goto again; | ||||
ccUnsubmitted Done Inline ActionsIf TSO is on, this is the number of max TSO chunks to be out, not packets. cc: If TSO is on, this is the number of max TSO chunks to be out, not packets. | |||||
rscheffAuthorUnsubmitted Done Inline ActionsYes, I have not looked into dealing with TSO chunks; Ideally, that should be taken into account as well... rscheff: Yes, I have not looked into dealing with TSO chunks; Ideally, that should be taken into account… | |||||
#endif | #else | ||||
if (sendalot) | if (sendalot) | ||||
goto again; | goto again; | ||||
#endif | |||||
return (0); | return (0); | ||||
} | } | ||||
void | void | ||||
tcp_setpersist(struct tcpcb *tp) | tcp_setpersist(struct tcpcb *tp) | ||||
{ | { | ||||
int t = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1; | int t = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1; | ||||
int tt; | int tt; | ||||
▲ Show 20 Lines • Show All 387 Lines • Show Last 20 Lines |
Can you elaborate how this translates to max cwnd/2? Is that divide and then multiply (tp->snd_cwnd>>1) again necessary?