Adds a new Congestion Control that helps reduce
the RTT that a flow will build up in buffers in transit. It is a slight modification to RFC2581 but is more friendly i.e. less aggressive. MFC after: 3 months
This commit is contained in:
parent
7d66f0801b
commit
48b6c64938
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=219120
@ -258,6 +258,11 @@ struct sctp_paramhdr {
|
||||
#define SCTP_CC_HSTCP 0x00000001
|
||||
/* HTCP Congestion Control */
|
||||
#define SCTP_CC_HTCP 0x00000002
|
||||
/* RTCC Congestion Control - RFC2581 plus */
|
||||
#define SCTP_CC_RTCC 0x00000003
|
||||
|
||||
#define SCTP_CC_OPT_RTCC_SETMODE 0x00002000
|
||||
#define SCTP_CC_OPT_USE_DCCC_ECN 0x00002001
|
||||
|
||||
/* RS - Supported stream scheduling modules for pluggable
|
||||
* stream scheduling
|
||||
|
@ -185,10 +185,203 @@ sctp_cwnd_update_after_fr(struct sctp_tcb *stcb,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* RTCC Algoritm to limit growth of cwnd, return
|
||||
* true if you want to NOT allow cwnd growth
|
||||
*/
|
||||
static int
|
||||
cc_bw_limit(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw)
|
||||
{
|
||||
uint64_t bw_offset, rtt_offset, rtt, vtag, probepoint;
|
||||
|
||||
/*-
|
||||
* Here we need to see if we want
|
||||
* to limit cwnd growth due to increase
|
||||
* in overall rtt but no increase in bw.
|
||||
* We use the following table to figure
|
||||
* out what we should do. When we return
|
||||
* 0, cc update goes on as planned. If we
|
||||
* return 1, then no cc update happens and cwnd
|
||||
* stays where it is at.
|
||||
* ----------------------------------
|
||||
* BW | RTT | Action
|
||||
* *********************************
|
||||
* INC | INC | return 0
|
||||
* ----------------------------------
|
||||
* INC | SAME | return 0
|
||||
* ----------------------------------
|
||||
* INC | DECR | return 0
|
||||
* ----------------------------------
|
||||
* SAME | INC | return 1
|
||||
* ----------------------------------
|
||||
* SAME | SAME | return 1
|
||||
* ----------------------------------
|
||||
* SAME | DECR | return 0
|
||||
* ----------------------------------
|
||||
* DECR | INC | return 0 or 1 based on if we caused.
|
||||
* ----------------------------------
|
||||
* DECR | SAME | return 0
|
||||
* ----------------------------------
|
||||
* DECR | DECR | return 0
|
||||
* ----------------------------------
|
||||
*
|
||||
* We are a bit fuzz on what an increase or
|
||||
* decrease is. For BW it is the same if
|
||||
* it did not change within 1/64th. For
|
||||
* RTT it stayed the same if it did not
|
||||
* change within 1/32nd
|
||||
*/
|
||||
rtt = stcb->asoc.my_vtag;
|
||||
vtag = (rtt << 32) | (((uint32_t) (stcb->sctp_ep->sctp_lport)) << 16) | (stcb->rport);
|
||||
probepoint = (((uint64_t) net->cwnd) << 32);
|
||||
rtt = net->rtt;
|
||||
bw_offset = net->cc_mod.rtcc.lbw >> SCTP_BASE_SYSCTL(sctp_rttvar_bw);
|
||||
if (nbw > net->cc_mod.rtcc.lbw + bw_offset) {
|
||||
/*
|
||||
* BW increased, so update and return 0, since all actions
|
||||
* in our table say to do the normal CC update
|
||||
*/
|
||||
/* PROBE POINT 0 */
|
||||
SDT_PROBE(sctp, cwnd, net, rttvar,
|
||||
vtag,
|
||||
((net->cc_mod.rtcc.lbw << 32) | nbw),
|
||||
net->cc_mod.rtcc.lbw_rtt,
|
||||
rtt,
|
||||
probepoint);
|
||||
net->cc_mod.rtcc.lbw = nbw;
|
||||
net->cc_mod.rtcc.lbw_rtt = rtt;
|
||||
net->cc_mod.rtcc.cwnd_at_bw_set = net->cwnd;
|
||||
return (0);
|
||||
}
|
||||
rtt_offset = net->cc_mod.rtcc.lbw_rtt >> SCTP_BASE_SYSCTL(sctp_rttvar_rtt);
|
||||
if (nbw < net->cc_mod.rtcc.lbw - bw_offset) {
|
||||
/* Bandwidth decreased. */
|
||||
if (rtt > net->cc_mod.rtcc.lbw_rtt + rtt_offset) {
|
||||
/* rtt increased */
|
||||
/* Did we add more */
|
||||
if (net->cwnd > net->cc_mod.rtcc.cwnd_at_bw_set) {
|
||||
/* We caused it maybe.. back off */
|
||||
/* PROBE POINT 1 */
|
||||
probepoint |= ((1 << 16) | 1);
|
||||
SDT_PROBE(sctp, cwnd, net, rttvar,
|
||||
vtag,
|
||||
((net->cc_mod.rtcc.lbw << 32) | nbw),
|
||||
net->cc_mod.rtcc.lbw_rtt,
|
||||
rtt,
|
||||
probepoint);
|
||||
|
||||
net->cc_mod.rtcc.lbw = nbw;
|
||||
net->cc_mod.rtcc.lbw_rtt = rtt;
|
||||
net->cwnd = net->cc_mod.rtcc.cwnd_at_bw_set;
|
||||
if (net->cc_mod.rtcc.ret_from_eq) {
|
||||
/*
|
||||
* Switch over to CA if we are less
|
||||
* aggressive
|
||||
*/
|
||||
net->ssthresh = net->cwnd - 1;
|
||||
net->partial_bytes_acked = 0;
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
/* Probe point 2 */
|
||||
probepoint |= ((2 << 16) | 0);
|
||||
SDT_PROBE(sctp, cwnd, net, rttvar,
|
||||
vtag,
|
||||
((net->cc_mod.rtcc.lbw << 32) | nbw),
|
||||
net->cc_mod.rtcc.lbw_rtt,
|
||||
rtt,
|
||||
probepoint);
|
||||
|
||||
/* Someone else - fight for more? */
|
||||
net->cc_mod.rtcc.lbw = nbw;
|
||||
net->cc_mod.rtcc.lbw_rtt = rtt;
|
||||
net->cc_mod.rtcc.cwnd_at_bw_set = net->cwnd;
|
||||
return (0);
|
||||
} else if (rtt < net->cc_mod.rtcc.lbw_rtt - rtt_offset) {
|
||||
/* rtt decreased */
|
||||
/* Probe point 3 */
|
||||
probepoint |= ((3 << 16) | 0);
|
||||
SDT_PROBE(sctp, cwnd, net, rttvar,
|
||||
vtag,
|
||||
((net->cc_mod.rtcc.lbw << 32) | nbw),
|
||||
net->cc_mod.rtcc.lbw_rtt,
|
||||
rtt,
|
||||
probepoint);
|
||||
net->cc_mod.rtcc.lbw = nbw;
|
||||
net->cc_mod.rtcc.lbw_rtt = rtt;
|
||||
net->cc_mod.rtcc.cwnd_at_bw_set = net->cwnd;
|
||||
return (0);
|
||||
}
|
||||
/* The bw decreased but rtt stayed the same */
|
||||
net->cc_mod.rtcc.lbw = nbw;
|
||||
net->cc_mod.rtcc.lbw_rtt = rtt;
|
||||
net->cc_mod.rtcc.cwnd_at_bw_set = net->cwnd;
|
||||
/* Probe point 4 */
|
||||
probepoint |= ((4 << 16) | 0);
|
||||
SDT_PROBE(sctp, cwnd, net, rttvar,
|
||||
vtag,
|
||||
((net->cc_mod.rtcc.lbw << 32) | nbw),
|
||||
net->cc_mod.rtcc.lbw_rtt,
|
||||
rtt,
|
||||
probepoint);
|
||||
return (0);
|
||||
}
|
||||
/*
|
||||
* If we reach here then we are in a situation where the bw stayed
|
||||
* the same.
|
||||
*/
|
||||
if (rtt > net->cc_mod.rtcc.lbw_rtt + rtt_offset) {
|
||||
/*
|
||||
* rtt increased we don't update bw.. so we don't update the
|
||||
* rtt either.
|
||||
*/
|
||||
/* Probe point 5 */
|
||||
probepoint |= ((5 << 16) | 1);
|
||||
SDT_PROBE(sctp, cwnd, net, rttvar,
|
||||
vtag,
|
||||
((net->cc_mod.rtcc.lbw << 32) | nbw),
|
||||
net->cc_mod.rtcc.lbw_rtt,
|
||||
rtt,
|
||||
probepoint);
|
||||
return (1);
|
||||
}
|
||||
if (rtt < net->cc_mod.rtcc.lbw_rtt - rtt_offset) {
|
||||
/*
|
||||
* rtt decreased, there could be more room. we update both
|
||||
* the bw and the rtt here.
|
||||
*/
|
||||
/* Probe point 6 */
|
||||
probepoint |= ((6 << 16) | 0);
|
||||
SDT_PROBE(sctp, cwnd, net, rttvar,
|
||||
vtag,
|
||||
((net->cc_mod.rtcc.lbw << 32) | nbw),
|
||||
net->cc_mod.rtcc.lbw_rtt,
|
||||
rtt,
|
||||
probepoint);
|
||||
net->cc_mod.rtcc.lbw = nbw;
|
||||
net->cc_mod.rtcc.lbw_rtt = rtt;
|
||||
net->cc_mod.rtcc.cwnd_at_bw_set = net->cwnd;
|
||||
return (0);
|
||||
}
|
||||
/*
|
||||
* Ok bw and rtt remained the same .. no update to any but save the
|
||||
* latest cwnd.
|
||||
*/
|
||||
/* Probe point 7 */
|
||||
probepoint |= ((7 << 16) | net->cc_mod.rtcc.ret_from_eq);
|
||||
SDT_PROBE(sctp, cwnd, net, rttvar,
|
||||
vtag,
|
||||
((net->cc_mod.rtcc.lbw << 32) | nbw),
|
||||
net->cc_mod.rtcc.lbw_rtt,
|
||||
rtt,
|
||||
probepoint);
|
||||
return ((int)net->cc_mod.rtcc.ret_from_eq);
|
||||
}
|
||||
|
||||
static void
|
||||
sctp_cwnd_update_after_sack(struct sctp_tcb *stcb,
|
||||
sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb,
|
||||
struct sctp_association *asoc,
|
||||
int accum_moved, int reneged_all, int will_exit)
|
||||
int accum_moved, int reneged_all, int will_exit, int use_rtcc)
|
||||
{
|
||||
struct sctp_nets *net;
|
||||
int old_cwnd;
|
||||
@ -326,6 +519,48 @@ sctp_cwnd_update_after_sack(struct sctp_tcb *stcb,
|
||||
*/
|
||||
goto skip_cwnd_update;
|
||||
}
|
||||
/*
|
||||
* Did any measurements go on for this network?
|
||||
*/
|
||||
if (use_rtcc && (net->cc_mod.rtcc.tls_needs_set > 0)) {
|
||||
uint64_t nbw;
|
||||
|
||||
/*
|
||||
* At this point our bw_bytes has been updated by
|
||||
* incoming sack information.
|
||||
*
|
||||
* But our bw may not yet be set.
|
||||
*
|
||||
*/
|
||||
if ((net->cc_mod.rtcc.new_tot_time / 1000) > 0) {
|
||||
nbw = net->cc_mod.rtcc.bw_bytes / (net->cc_mod.rtcc.new_tot_time / 1000);
|
||||
} else {
|
||||
nbw = net->cc_mod.rtcc.bw_bytes;
|
||||
}
|
||||
if (net->cc_mod.rtcc.lbw) {
|
||||
if (cc_bw_limit(stcb, net, nbw)) {
|
||||
/* Hold here, no update */
|
||||
goto skip_cwnd_update;
|
||||
}
|
||||
} else {
|
||||
uint64_t vtag, probepoint;
|
||||
|
||||
probepoint = (((uint64_t) net->cwnd) << 32);
|
||||
probepoint |= ((0xa << 16) | 0);
|
||||
vtag = (net->rtt << 32) |
|
||||
(((uint32_t) (stcb->sctp_ep->sctp_lport)) << 16) |
|
||||
(stcb->rport);
|
||||
|
||||
SDT_PROBE(sctp, cwnd, net, rttvar,
|
||||
vtag,
|
||||
nbw,
|
||||
0,
|
||||
net->rtt,
|
||||
probepoint);
|
||||
net->cc_mod.rtcc.lbw = nbw;
|
||||
net->cc_mod.rtcc.lbw_rtt = net->rtt;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* CMT: CUC algorithm. Update cwnd if pseudo-cumack has
|
||||
* moved.
|
||||
@ -481,31 +716,67 @@ sctp_cwnd_update_after_timeout(struct sctp_tcb *stcb, struct sctp_nets *net)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
sctp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net,
|
||||
int in_window, int num_pkt_lost)
|
||||
sctp_cwnd_update_after_ecn_echo_common(struct sctp_tcb *stcb, struct sctp_nets *net,
|
||||
int in_window, int num_pkt_lost, int use_rtcc)
|
||||
{
|
||||
int old_cwnd = net->cwnd;
|
||||
|
||||
if (in_window == 0) {
|
||||
SCTP_STAT_INCR(sctps_ecnereducedcwnd);
|
||||
net->ssthresh = net->cwnd / 2;
|
||||
if (net->ssthresh < net->mtu) {
|
||||
net->ssthresh = net->mtu;
|
||||
/* here back off the timer as well, to slow us down */
|
||||
net->RTO <<= 1;
|
||||
if ((use_rtcc) && (net->lan_type == SCTP_LAN_LOCAL) && (net->cc_mod.rtcc.use_dccc_ecn)) {
|
||||
/* Data center Congestion Control */
|
||||
if (in_window == 0) {
|
||||
/*
|
||||
* Go to CA with the cwnd at the point we sent the
|
||||
* TSN that was marked with a CE.
|
||||
*/
|
||||
if (net->ecn_prev_cwnd < net->cwnd) {
|
||||
/* Restore to prev cwnd */
|
||||
net->cwnd = net->ecn_prev_cwnd - (net->mtu * num_pkt_lost);
|
||||
} else {
|
||||
/* Just cut in 1/2 */
|
||||
net->cwnd /= 2;
|
||||
}
|
||||
/* Drop to CA */
|
||||
net->ssthresh = net->cwnd - (num_pkt_lost * net->mtu);
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
|
||||
sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Further tuning down required over the drastic
|
||||
* orginal cut
|
||||
*/
|
||||
net->ssthresh -= (net->mtu * num_pkt_lost);
|
||||
net->cwnd -= (net->mtu * num_pkt_lost);
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
|
||||
sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT);
|
||||
}
|
||||
}
|
||||
net->cwnd = net->ssthresh;
|
||||
SDT_PROBE(sctp, cwnd, net, ecn,
|
||||
stcb->asoc.my_vtag,
|
||||
((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
|
||||
net,
|
||||
old_cwnd, net->cwnd);
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
|
||||
sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT);
|
||||
SCTP_STAT_INCR(sctps_ecnereducedcwnd);
|
||||
} else {
|
||||
if (in_window == 0) {
|
||||
SCTP_STAT_INCR(sctps_ecnereducedcwnd);
|
||||
net->ssthresh = net->cwnd / 2;
|
||||
if (net->ssthresh < net->mtu) {
|
||||
net->ssthresh = net->mtu;
|
||||
/*
|
||||
* here back off the timer as well, to slow
|
||||
* us down
|
||||
*/
|
||||
net->RTO <<= 1;
|
||||
}
|
||||
net->cwnd = net->ssthresh;
|
||||
SDT_PROBE(sctp, cwnd, net, ecn,
|
||||
stcb->asoc.my_vtag,
|
||||
((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
|
||||
net,
|
||||
old_cwnd, net->cwnd);
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
|
||||
sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SAT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
@ -636,14 +907,16 @@ sctp_cwnd_update_after_output(struct sctp_tcb *stcb,
|
||||
|
||||
if (net->ssthresh < net->cwnd)
|
||||
net->ssthresh = net->cwnd;
|
||||
net->cwnd = (net->flight_size + (burst_limit * net->mtu));
|
||||
SDT_PROBE(sctp, cwnd, net, bl,
|
||||
stcb->asoc.my_vtag,
|
||||
((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
|
||||
net,
|
||||
old_cwnd, net->cwnd);
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
|
||||
sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_BRST);
|
||||
if (burst_limit) {
|
||||
net->cwnd = (net->flight_size + (burst_limit * net->mtu));
|
||||
SDT_PROBE(sctp, cwnd, net, bl,
|
||||
stcb->asoc.my_vtag,
|
||||
((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
|
||||
net,
|
||||
old_cwnd, net->cwnd);
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
|
||||
sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_BRST);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -673,6 +946,212 @@ sctp_cwnd_update_after_fr_timer(struct sctp_inpcb *inp,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sctp_cwnd_update_after_sack(struct sctp_tcb *stcb,
|
||||
struct sctp_association *asoc,
|
||||
int accum_moved, int reneged_all, int will_exit)
|
||||
{
|
||||
/* Passing a zero argument in last disables the rtcc algoritm */
|
||||
sctp_cwnd_update_after_sack_common(stcb, asoc, accum_moved, reneged_all, will_exit, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
sctp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net,
|
||||
int in_window, int num_pkt_lost)
|
||||
{
|
||||
/* Passing a zero argument in last disables the rtcc algoritm */
|
||||
sctp_cwnd_update_after_ecn_echo_common(stcb, net, in_window, num_pkt_lost, 0);
|
||||
}
|
||||
|
||||
/* Here starts the RTCCVAR type CC invented by RRS which
|
||||
* is a slight mod to RFC2581. We reuse a common routine or
|
||||
* two since these algoritms are so close and need to
|
||||
* remain the same.
|
||||
*/
|
||||
static void
|
||||
sctp_cwnd_update_rtcc_after_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net,
|
||||
int in_window, int num_pkt_lost)
|
||||
{
|
||||
sctp_cwnd_update_after_ecn_echo_common(stcb, net, in_window, num_pkt_lost, 1);
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void
|
||||
sctp_cwnd_update_rtcc_tsn_acknowledged(struct sctp_nets *net,
|
||||
struct sctp_tmit_chunk *tp1)
|
||||
{
|
||||
net->cc_mod.rtcc.bw_bytes += tp1->send_size;
|
||||
}
|
||||
|
||||
static void
|
||||
sctp_cwnd_prepare_rtcc_net_for_sack(struct sctp_tcb *stcb,
|
||||
struct sctp_nets *net)
|
||||
{
|
||||
if (net->cc_mod.rtcc.tls_needs_set > 0) {
|
||||
/* We had a bw measurment going on */
|
||||
struct timeval ltls;
|
||||
|
||||
SCTP_GETPTIME_TIMEVAL(<ls);
|
||||
timevalsub(<ls, &net->cc_mod.rtcc.tls);
|
||||
net->cc_mod.rtcc.new_tot_time = (ltls.tv_sec * 1000000) + ltls.tv_usec;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sctp_cwnd_new_rtcc_transmission_begins(struct sctp_tcb *stcb,
|
||||
struct sctp_nets *net)
|
||||
{
|
||||
uint64_t vtag, probepoint;
|
||||
|
||||
if (net->cc_mod.rtcc.lbw) {
|
||||
/* Clear the old bw.. we went to 0 in-flight */
|
||||
vtag = (net->rtt << 32) | (((uint32_t) (stcb->sctp_ep->sctp_lport)) << 16) |
|
||||
(stcb->rport);
|
||||
probepoint = (((uint64_t) net->cwnd) << 32);
|
||||
/* Probe point 8 */
|
||||
probepoint |= ((8 << 16) | 0);
|
||||
SDT_PROBE(sctp, cwnd, net, rttvar,
|
||||
vtag,
|
||||
((net->cc_mod.rtcc.lbw << 32) | 0),
|
||||
net->cc_mod.rtcc.lbw_rtt,
|
||||
0,
|
||||
probepoint);
|
||||
net->cc_mod.rtcc.lbw_rtt = 0;
|
||||
net->cc_mod.rtcc.cwnd_at_bw_set = 0;
|
||||
net->cc_mod.rtcc.lbw = 0;
|
||||
net->cc_mod.rtcc.bw_tot_time = 0;
|
||||
net->cc_mod.rtcc.bw_bytes = 0;
|
||||
net->cc_mod.rtcc.tls_needs_set = 0;
|
||||
if (net->cc_mod.rtcc.ret_from_eq) {
|
||||
/* less aggressive one - reset cwnd too */
|
||||
uint32_t cwnd_in_mtu, cwnd;
|
||||
|
||||
cwnd_in_mtu = SCTP_BASE_SYSCTL(sctp_initial_cwnd);
|
||||
if (cwnd_in_mtu == 0) {
|
||||
/*
|
||||
* Using 0 means that the value of RFC 4960
|
||||
* is used.
|
||||
*/
|
||||
cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND));
|
||||
} else {
|
||||
/*
|
||||
* We take the minimum of the burst limit
|
||||
* and the initial congestion window.
|
||||
*/
|
||||
if ((stcb->asoc.max_burst > 0) && (cwnd_in_mtu > stcb->asoc.max_burst))
|
||||
cwnd_in_mtu = stcb->asoc.max_burst;
|
||||
cwnd = (net->mtu - sizeof(struct sctphdr)) * cwnd_in_mtu;
|
||||
}
|
||||
if (net->cwnd > cwnd) {
|
||||
/*
|
||||
* Only set if we are not a timeout (i.e.
|
||||
* down to 1 mtu)
|
||||
*/
|
||||
net->cwnd = cwnd;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sctp_set_rtcc_initial_cc_param(struct sctp_tcb *stcb,
|
||||
struct sctp_nets *net)
|
||||
{
|
||||
uint64_t vtag, probepoint;
|
||||
|
||||
sctp_set_initial_cc_param(stcb, net);
|
||||
stcb->asoc.use_precise_time = 1;
|
||||
probepoint = (((uint64_t) net->cwnd) << 32);
|
||||
probepoint |= ((9 << 16) | 0);
|
||||
vtag = (net->rtt << 32) |
|
||||
(((uint32_t) (stcb->sctp_ep->sctp_lport)) << 16) |
|
||||
(stcb->rport);
|
||||
SDT_PROBE(sctp, cwnd, net, rttvar,
|
||||
vtag,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
probepoint);
|
||||
net->cc_mod.rtcc.lbw_rtt = 0;
|
||||
net->cc_mod.rtcc.cwnd_at_bw_set = 0;
|
||||
net->cc_mod.rtcc.lbw = 0;
|
||||
net->cc_mod.rtcc.bw_tot_time = 0;
|
||||
net->cc_mod.rtcc.bw_bytes = 0;
|
||||
net->cc_mod.rtcc.tls_needs_set = 0;
|
||||
net->cc_mod.rtcc.ret_from_eq = SCTP_BASE_SYSCTL(sctp_rttvar_eqret);
|
||||
}
|
||||
|
||||
static int
|
||||
sctp_cwnd_rtcc_socket_option(struct sctp_tcb *stcb, int setorget,
|
||||
struct sctp_cc_option *cc_opt)
|
||||
{
|
||||
struct sctp_nets *net;
|
||||
|
||||
if (setorget == 1) {
|
||||
/* a set */
|
||||
if (cc_opt->option == SCTP_CC_OPT_RTCC_SETMODE) {
|
||||
if ((cc_opt->aid_value.assoc_value != 0) &&
|
||||
(cc_opt->aid_value.assoc_value != 1)) {
|
||||
return (EINVAL);
|
||||
}
|
||||
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
|
||||
net->cc_mod.rtcc.ret_from_eq = cc_opt->aid_value.assoc_value;
|
||||
}
|
||||
} else if (cc_opt->option == SCTP_CC_OPT_USE_DCCC_ECN) {
|
||||
if ((cc_opt->aid_value.assoc_value != 0) &&
|
||||
(cc_opt->aid_value.assoc_value != 1)) {
|
||||
return (EINVAL);
|
||||
}
|
||||
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
|
||||
net->cc_mod.rtcc.use_dccc_ecn = cc_opt->aid_value.assoc_value;
|
||||
}
|
||||
} else {
|
||||
return (EINVAL);
|
||||
}
|
||||
} else {
|
||||
/* a get */
|
||||
if (cc_opt->option == SCTP_CC_OPT_RTCC_SETMODE) {
|
||||
net = TAILQ_FIRST(&stcb->asoc.nets);
|
||||
if (net == NULL) {
|
||||
return (EFAULT);
|
||||
}
|
||||
cc_opt->aid_value.assoc_value = net->cc_mod.rtcc.ret_from_eq;
|
||||
} else if (cc_opt->option == SCTP_CC_OPT_USE_DCCC_ECN) {
|
||||
net = TAILQ_FIRST(&stcb->asoc.nets);
|
||||
if (net == NULL) {
|
||||
return (EFAULT);
|
||||
}
|
||||
cc_opt->aid_value.assoc_value = net->cc_mod.rtcc.use_dccc_ecn;
|
||||
} else {
|
||||
return (EINVAL);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
sctp_cwnd_update_rtcc_packet_transmitted(struct sctp_tcb *stcb,
|
||||
struct sctp_nets *net)
|
||||
{
|
||||
if (net->cc_mod.rtcc.tls_needs_set == 0) {
|
||||
SCTP_GETPTIME_TIMEVAL(&net->cc_mod.rtcc.tls);
|
||||
net->cc_mod.rtcc.tls_needs_set = 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sctp_cwnd_update_rtcc_after_sack(struct sctp_tcb *stcb,
|
||||
struct sctp_association *asoc,
|
||||
int accum_moved, int reneged_all, int will_exit)
|
||||
{
|
||||
/* Passing a one argument at the last enables the rtcc algoritm */
|
||||
sctp_cwnd_update_after_sack_common(stcb, asoc, accum_moved, reneged_all, will_exit, 1);
|
||||
}
|
||||
|
||||
|
||||
/* Here starts Sally Floyds HS-TCP */
|
||||
|
||||
struct sctp_hs_raise_drop {
|
||||
int32_t cwnd;
|
||||
int32_t increase;
|
||||
@ -1710,5 +2189,20 @@ struct sctp_cc_functions sctp_cc_functions[] = {
|
||||
.sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
|
||||
.sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
|
||||
.sctp_cwnd_update_after_fr_timer = sctp_htcp_cwnd_update_after_fr_timer
|
||||
},
|
||||
{
|
||||
.sctp_set_initial_cc_param = sctp_set_rtcc_initial_cc_param,
|
||||
.sctp_cwnd_update_after_sack = sctp_cwnd_update_rtcc_after_sack,
|
||||
.sctp_cwnd_update_after_fr = sctp_cwnd_update_after_fr,
|
||||
.sctp_cwnd_update_after_timeout = sctp_cwnd_update_after_timeout,
|
||||
.sctp_cwnd_update_after_ecn_echo = sctp_cwnd_update_rtcc_after_ecn_echo,
|
||||
.sctp_cwnd_update_after_packet_dropped = sctp_cwnd_update_after_packet_dropped,
|
||||
.sctp_cwnd_update_after_output = sctp_cwnd_update_after_output,
|
||||
.sctp_cwnd_update_after_fr_timer = sctp_cwnd_update_after_fr_timer,
|
||||
.sctp_cwnd_update_packet_transmitted = sctp_cwnd_update_rtcc_packet_transmitted,
|
||||
.sctp_cwnd_update_tsn_acknowledged = sctp_cwnd_update_rtcc_tsn_acknowledged,
|
||||
.sctp_cwnd_new_transmission_begins = sctp_cwnd_new_rtcc_transmission_begins,
|
||||
.sctp_cwnd_prepare_net_for_sack = sctp_cwnd_prepare_rtcc_net_for_sack,
|
||||
.sctp_cwnd_socket_option = sctp_cwnd_rtcc_socket_option
|
||||
}
|
||||
};
|
||||
|
@ -965,10 +965,9 @@ __FBSDID("$FreeBSD$");
|
||||
* local lan type rtt's
|
||||
*/
|
||||
/*
|
||||
* We allow 500us for the rtt and another 500us for the cookie processing
|
||||
* since we measure this on the first rtt.
|
||||
* We allow 900us for the rtt.
|
||||
*/
|
||||
#define SCTP_LOCAL_LAN_RTT 1100
|
||||
#define SCTP_LOCAL_LAN_RTT 900
|
||||
#define SCTP_LAN_UNKNOWN 0
|
||||
#define SCTP_LAN_LOCAL 1
|
||||
#define SCTP_LAN_INTERNET 2
|
||||
|
@ -219,6 +219,21 @@ struct htcp {
|
||||
uint32_t lasttime;
|
||||
};
|
||||
|
||||
struct rtcc_cc {
|
||||
struct timeval tls; /* The time we started the sending */
|
||||
uint64_t lbw; /* Our last estimated bw */
|
||||
uint64_t lbw_rtt; /* RTT at bw estimate */
|
||||
uint64_t bw_bytes; /* The total bytes since this sending began */
|
||||
uint64_t bw_tot_time; /* The total time since sending began */
|
||||
uint64_t new_tot_time; /* temp holding the new value */
|
||||
uint32_t cwnd_at_bw_set;
|
||||
uint8_t ret_from_eq;
|
||||
uint8_t use_dccc_ecn;
|
||||
uint8_t tls_needs_set; /* Flag to indicate we need to set tls 0 or 1
|
||||
* means set at send 2 not */
|
||||
};
|
||||
|
||||
|
||||
struct sctp_nets {
|
||||
TAILQ_ENTRY(sctp_nets) sctp_next; /* next link */
|
||||
|
||||
@ -255,6 +270,7 @@ struct sctp_nets {
|
||||
struct timeval last_sent_time;
|
||||
union cc_control_data {
|
||||
struct htcp htcp_ca; /* JRS - struct used in HTCP algorithm */
|
||||
struct rtcc_cc rtcc; /* rtcc module cc stuff */
|
||||
} cc_mod;
|
||||
int ref_count;
|
||||
|
||||
|
@ -115,11 +115,9 @@ sctp_init_sysctls()
|
||||
SCTP_BASE_SYSCTL(sctp_vtag_time_wait) = SCTPCTL_TIME_WAIT_DEFAULT;
|
||||
SCTP_BASE_SYSCTL(sctp_buffer_splitting) = SCTPCTL_BUFFER_SPLITTING_DEFAULT;
|
||||
SCTP_BASE_SYSCTL(sctp_initial_cwnd) = SCTPCTL_INITIAL_CWND_DEFAULT;
|
||||
#ifdef SCTP_HAS_RTTCC
|
||||
SCTP_BASE_SYSCTL(sctp_rttvar_bw) = SCTPCTL_RTTVAR_BW_DEFAULT;
|
||||
SCTP_BASE_SYSCTL(sctp_rttvar_rtt) = SCTPCTL_RTTVAR_RTT_DEFAULT;
|
||||
SCTP_BASE_SYSCTL(sctp_rttvar_eqret) = SCTPCTL_RTTVAR_EQRET_DEFAULT;
|
||||
#endif
|
||||
#if defined(SCTP_LOCAL_TRACE_BUF)
|
||||
memset(&SCTP_BASE_SYSCTL(sctp_log), 0, sizeof(struct sctp_log));
|
||||
#endif
|
||||
@ -638,11 +636,9 @@ sysctl_sctp_check(SYSCTL_HANDLER_ARGS)
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_vtag_time_wait), SCTPCTL_TIME_WAIT_MIN, SCTPCTL_TIME_WAIT_MAX);
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_buffer_splitting), SCTPCTL_BUFFER_SPLITTING_MIN, SCTPCTL_BUFFER_SPLITTING_MAX);
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_initial_cwnd), SCTPCTL_INITIAL_CWND_MIN, SCTPCTL_INITIAL_CWND_MAX);
|
||||
#ifdef SCTP_HAS_RTTCC
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_rttvar_bw), SCTPCTL_RTTVAR_BW_MIN, SCTPCTL_RTTVAR_BW_MAX);
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_rttvar_rtt), SCTPCTL_RTTVAR_RTT_MIN, SCTPCTL_RTTVAR_RTT_MAX);
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_rttvar_eqret), SCTPCTL_RTTVAR_EQRET_MIN, SCTPCTL_RTTVAR_EQRET_MAX);
|
||||
#endif
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_mobility_base), SCTPCTL_MOBILITY_BASE_MIN, SCTPCTL_MOBILITY_BASE_MAX);
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_mobility_fasthandoff), SCTPCTL_MOBILITY_FASTHANDOFF_MIN, SCTPCTL_MOBILITY_FASTHANDOFF_MAX);
|
||||
RANGECHK(SCTP_BASE_SYSCTL(sctp_udp_tunneling_for_client_enable), SCTPCTL_UDP_TUNNELING_FOR_CLIENT_ENABLE_MIN, SCTPCTL_UDP_TUNNELING_FOR_CLIENT_ENABLE_MAX);
|
||||
@ -1110,7 +1106,6 @@ SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, initial_cwnd, CTLTYPE_UINT | CTLFLAG_
|
||||
&SCTP_BASE_SYSCTL(sctp_initial_cwnd), 0, sysctl_sctp_check, "IU",
|
||||
SCTPCTL_INITIAL_CWND_DESC);
|
||||
|
||||
#ifdef SCTP_HAS_RTTCC
|
||||
SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, rttvar_bw, CTLTYPE_UINT | CTLFLAG_RW,
|
||||
&SCTP_BASE_SYSCTL(sctp_rttvar_bw), 0, sysctl_sctp_check, "IU",
|
||||
SCTPCTL_RTTVAR_BW_DESC);
|
||||
@ -1122,7 +1117,6 @@ SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, rttvar_rtt, CTLTYPE_UINT | CTLFLAG_RW
|
||||
SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, rttvar_eqret, CTLTYPE_UINT | CTLFLAG_RW,
|
||||
&SCTP_BASE_SYSCTL(sctp_rttvar_eqret), 0, sysctl_sctp_check, "IU",
|
||||
SCTPCTL_RTTVAR_EQRET_DESC);
|
||||
#endif
|
||||
|
||||
#ifdef SCTP_DEBUG
|
||||
SYSCTL_VNET_PROC(_net_inet_sctp, OID_AUTO, debug, CTLTYPE_UINT | CTLFLAG_RW,
|
||||
|
@ -104,11 +104,9 @@ struct sctp_sysctl {
|
||||
uint32_t sctp_mobility_base;
|
||||
uint32_t sctp_mobility_fasthandoff;
|
||||
uint32_t sctp_inits_include_nat_friendly;
|
||||
#ifdef SCTP_HAS_RTTCC
|
||||
uint32_t sctp_rttvar_bw;
|
||||
uint32_t sctp_rttvar_rtt;
|
||||
uint32_t sctp_rttvar_eqret;
|
||||
#endif
|
||||
#if defined(SCTP_LOCAL_TRACE_BUF)
|
||||
struct sctp_log sctp_log;
|
||||
#endif
|
||||
@ -519,7 +517,6 @@ struct sctp_sysctl {
|
||||
#define SCTPCTL_INITIAL_CWND_MIN 0
|
||||
#define SCTPCTL_INITIAL_CWND_MAX 0xffffffff
|
||||
#define SCTPCTL_INITIAL_CWND_DEFAULT 3
|
||||
#ifdef SCTP_HAS_RTTCC
|
||||
|
||||
/* rttvar smooth avg for bw calc */
|
||||
#define SCTPCTL_RTTVAR_BW_DESC "Shift amount for bw smothing on rtt calc"
|
||||
@ -537,7 +534,6 @@ struct sctp_sysctl {
|
||||
#define SCTPCTL_RTTVAR_EQRET_MIN 0
|
||||
#define SCTPCTL_RTTVAR_EQRET_MAX 1
|
||||
#define SCTPCTL_RTTVAR_EQRET_DEFAULT 0
|
||||
#endif
|
||||
|
||||
#if defined(SCTP_DEBUG)
|
||||
/* debug: Configure debug output */
|
||||
|
@ -1777,6 +1777,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
}
|
||||
}
|
||||
break;
|
||||
/* RS - Get socket option for pluggable stream scheduling */
|
||||
case SCTP_PLUGGABLE_SS:
|
||||
{
|
||||
@ -2957,6 +2958,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
case SCTP_CC_RFC2581:
|
||||
case SCTP_CC_HSTCP:
|
||||
case SCTP_CC_HTCP:
|
||||
case SCTP_CC_RTCC:
|
||||
stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value];
|
||||
stcb->asoc.congestion_control_module = av->assoc_value;
|
||||
if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) {
|
||||
@ -2976,6 +2978,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
case SCTP_CC_RFC2581:
|
||||
case SCTP_CC_HSTCP:
|
||||
case SCTP_CC_HTCP:
|
||||
case SCTP_CC_RTCC:
|
||||
SCTP_INP_WLOCK(inp);
|
||||
inp->sctp_ep.sctp_default_cc_module = av->assoc_value;
|
||||
SCTP_INP_WUNLOCK(inp);
|
||||
@ -2987,6 +2990,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SCTP_CC_OPTION:
|
||||
{
|
||||
struct sctp_cc_option *cc_opt;
|
||||
|
Loading…
Reference in New Issue
Block a user