Add a SCTP socket option to limit the cwnd for each path.
MFC after: 1 month
This commit is contained in:
parent
56c2c47b64
commit
59b6d5be4e
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=279859
@ -383,6 +383,9 @@ sctp_opt_info(int sd, sctp_assoc_t id, int opt, void *arg, socklen_t * size)
|
||||
case SCTP_PR_ASSOC_STATUS:
|
||||
((struct sctp_prstatus *)arg)->sprstat_assoc_id = id;
|
||||
break;
|
||||
case SCTP_MAX_CWND:
|
||||
((struct sctp_assoc_value *)arg)->assoc_id = id;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -128,6 +128,7 @@ struct sctp_paramhdr {
|
||||
#define SCTP_RECONFIG_SUPPORTED 0x00000029
|
||||
#define SCTP_NRSACK_SUPPORTED 0x00000030
|
||||
#define SCTP_PKTDROP_SUPPORTED 0x00000031
|
||||
#define SCTP_MAX_CWND 0x00000032
|
||||
|
||||
/*
|
||||
* read-only options
|
||||
|
@ -52,6 +52,19 @@ __FBSDID("$FreeBSD$");
|
||||
#define SHIFT_MPTCP_MULTI_Z 16
|
||||
#define SHIFT_MPTCP_MULTI 8
|
||||
|
||||
static void
|
||||
sctp_enforce_cwnd_limit(struct sctp_association *assoc, struct sctp_nets *net)
|
||||
{
|
||||
if ((assoc->max_cwnd > 0) &&
|
||||
(net->cwnd > assoc->max_cwnd) &&
|
||||
(net->cwnd > (net->mtu - sizeof(struct sctphdr)))) {
|
||||
net->cwnd = assoc->max_cwnd;
|
||||
if (net->cwnd < (net->mtu - sizeof(struct sctphdr))) {
|
||||
net->cwnd = net->mtu - sizeof(struct sctphdr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sctp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net)
|
||||
{
|
||||
@ -80,6 +93,7 @@ sctp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net)
|
||||
net->cwnd = net->mtu - sizeof(struct sctphdr);
|
||||
}
|
||||
}
|
||||
sctp_enforce_cwnd_limit(assoc, net);
|
||||
net->ssthresh = assoc->peers_rwnd;
|
||||
SDT_PROBE(sctp, cwnd, net, init,
|
||||
stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net,
|
||||
@ -178,6 +192,7 @@ sctp_cwnd_update_after_fr(struct sctp_tcb *stcb,
|
||||
}
|
||||
}
|
||||
net->cwnd = net->ssthresh;
|
||||
sctp_enforce_cwnd_limit(asoc, net);
|
||||
SDT_PROBE(sctp, cwnd, net, fr,
|
||||
stcb->asoc.my_vtag, ((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)), net,
|
||||
old_cwnd, net->cwnd);
|
||||
@ -426,6 +441,7 @@ cc_bw_decrease(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, uint6
|
||||
if ((net->cc_mod.rtcc.vol_reduce) &&
|
||||
(inst_ind != SCTP_INST_GAINING)) {
|
||||
net->cwnd += net->mtu;
|
||||
sctp_enforce_cwnd_limit(&stcb->asoc, net);
|
||||
net->cc_mod.rtcc.vol_reduce--;
|
||||
}
|
||||
net->cc_mod.rtcc.last_step_state = 2;
|
||||
@ -457,6 +473,7 @@ cc_bw_decrease(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, uint6
|
||||
if ((net->cc_mod.rtcc.vol_reduce) &&
|
||||
(inst_ind != SCTP_INST_GAINING)) {
|
||||
net->cwnd += net->mtu;
|
||||
sctp_enforce_cwnd_limit(&stcb->asoc, net);
|
||||
net->cc_mod.rtcc.vol_reduce--;
|
||||
}
|
||||
net->cc_mod.rtcc.last_step_state = 3;
|
||||
@ -488,6 +505,7 @@ cc_bw_decrease(struct sctp_tcb *stcb, struct sctp_nets *net, uint64_t nbw, uint6
|
||||
if ((net->cc_mod.rtcc.vol_reduce) &&
|
||||
(inst_ind != SCTP_INST_GAINING)) {
|
||||
net->cwnd += net->mtu;
|
||||
sctp_enforce_cwnd_limit(&stcb->asoc, net);
|
||||
net->cc_mod.rtcc.vol_reduce--;
|
||||
}
|
||||
net->cc_mod.rtcc.last_step_state = 4;
|
||||
@ -882,6 +900,7 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb,
|
||||
break;
|
||||
}
|
||||
net->cwnd += incr;
|
||||
sctp_enforce_cwnd_limit(asoc, net);
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
|
||||
sctp_log_cwnd(stcb, net, incr,
|
||||
SCTP_CWND_LOG_FROM_SS);
|
||||
@ -948,6 +967,7 @@ sctp_cwnd_update_after_sack_common(struct sctp_tcb *stcb,
|
||||
break;
|
||||
}
|
||||
net->cwnd += incr;
|
||||
sctp_enforce_cwnd_limit(asoc, net);
|
||||
SDT_PROBE(sctp, cwnd, net, ack,
|
||||
stcb->asoc.my_vtag,
|
||||
((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
|
||||
@ -1227,6 +1247,7 @@ sctp_cwnd_update_after_packet_dropped(struct sctp_tcb *stcb,
|
||||
/* We always have 1 MTU */
|
||||
net->cwnd = net->mtu;
|
||||
}
|
||||
sctp_enforce_cwnd_limit(&stcb->asoc, net);
|
||||
if (net->cwnd - old_cwnd != 0) {
|
||||
/* log only changes */
|
||||
SDT_PROBE(sctp, cwnd, net, pd,
|
||||
@ -1251,6 +1272,7 @@ sctp_cwnd_update_after_output(struct sctp_tcb *stcb,
|
||||
net->ssthresh = net->cwnd;
|
||||
if (burst_limit) {
|
||||
net->cwnd = (net->flight_size + (burst_limit * net->mtu));
|
||||
sctp_enforce_cwnd_limit(&stcb->asoc, net);
|
||||
SDT_PROBE(sctp, cwnd, net, bl,
|
||||
stcb->asoc.my_vtag,
|
||||
((stcb->sctp_ep->sctp_lport << 16) | (stcb->rport)),
|
||||
@ -1589,6 +1611,7 @@ static void
|
||||
sctp_hs_cwnd_increase(struct sctp_tcb *stcb, struct sctp_nets *net)
|
||||
{
|
||||
int cur_val, i, indx, incr;
|
||||
int old_cwnd = net->cwnd;
|
||||
|
||||
cur_val = net->cwnd >> 10;
|
||||
indx = SCTP_HS_TABLE_SIZE - 1;
|
||||
@ -1597,14 +1620,8 @@ sctp_hs_cwnd_increase(struct sctp_tcb *stcb, struct sctp_nets *net)
|
||||
/* normal mode */
|
||||
if (net->net_ack > net->mtu) {
|
||||
net->cwnd += net->mtu;
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
|
||||
sctp_log_cwnd(stcb, net, net->mtu, SCTP_CWND_LOG_FROM_SS);
|
||||
}
|
||||
} else {
|
||||
net->cwnd += net->net_ack;
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
|
||||
sctp_log_cwnd(stcb, net, net->net_ack, SCTP_CWND_LOG_FROM_SS);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i = net->last_hs_used; i < SCTP_HS_TABLE_SIZE; i++) {
|
||||
@ -1616,9 +1633,10 @@ sctp_hs_cwnd_increase(struct sctp_tcb *stcb, struct sctp_nets *net)
|
||||
net->last_hs_used = indx;
|
||||
incr = ((sctp_cwnd_adjust[indx].increase) << 10);
|
||||
net->cwnd += incr;
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
|
||||
sctp_log_cwnd(stcb, net, incr, SCTP_CWND_LOG_FROM_SS);
|
||||
}
|
||||
}
|
||||
sctp_enforce_cwnd_limit(&stcb->asoc, net);
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
|
||||
sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_SS);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1657,6 +1675,7 @@ sctp_hs_cwnd_decrease(struct sctp_tcb *stcb, struct sctp_nets *net)
|
||||
net->last_hs_used = indx;
|
||||
}
|
||||
}
|
||||
sctp_enforce_cwnd_limit(&stcb->asoc, net);
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
|
||||
sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_FR);
|
||||
}
|
||||
@ -1788,9 +1807,7 @@ sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb,
|
||||
if (net->cwnd <= net->ssthresh) {
|
||||
/* We are in slow start */
|
||||
if (net->flight_size + net->net_ack >= net->cwnd) {
|
||||
|
||||
sctp_hs_cwnd_increase(stcb, net);
|
||||
|
||||
} else {
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
|
||||
sctp_log_cwnd(stcb, net, net->net_ack,
|
||||
@ -1804,6 +1821,7 @@ sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb,
|
||||
(net->partial_bytes_acked >= net->cwnd)) {
|
||||
net->partial_bytes_acked -= net->cwnd;
|
||||
net->cwnd += net->mtu;
|
||||
sctp_enforce_cwnd_limit(asoc, net);
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
|
||||
sctp_log_cwnd(stcb, net, net->mtu,
|
||||
SCTP_CWND_LOG_FROM_CA);
|
||||
@ -2042,6 +2060,7 @@ htcp_cong_avoid(struct sctp_tcb *stcb, struct sctp_nets *net)
|
||||
SCTP_CWND_LOG_FROM_SS);
|
||||
}
|
||||
}
|
||||
sctp_enforce_cwnd_limit(&stcb->asoc, net);
|
||||
} else {
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) {
|
||||
sctp_log_cwnd(stcb, net, net->net_ack,
|
||||
@ -2063,6 +2082,7 @@ htcp_cong_avoid(struct sctp_tcb *stcb, struct sctp_nets *net)
|
||||
*/
|
||||
net->cwnd += net->mtu;
|
||||
net->partial_bytes_acked = 0;
|
||||
sctp_enforce_cwnd_limit(&stcb->asoc, net);
|
||||
htcp_alpha_update(&net->cc_mod.htcp_ca);
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
|
||||
sctp_log_cwnd(stcb, net, net->mtu,
|
||||
@ -2109,6 +2129,7 @@ sctp_htcp_set_initial_cc_param(struct sctp_tcb *stcb, struct sctp_nets *net)
|
||||
*/
|
||||
net->cwnd = min((net->mtu * 4), max((2 * net->mtu), SCTP_INITIAL_CWND));
|
||||
net->ssthresh = stcb->asoc.peers_rwnd;
|
||||
sctp_enforce_cwnd_limit(&stcb->asoc, net);
|
||||
htcp_init(net);
|
||||
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & (SCTP_CWND_MONITOR_ENABLE | SCTP_CWND_LOGGING_ENABLE)) {
|
||||
@ -2212,6 +2233,7 @@ sctp_htcp_cwnd_update_after_fr(struct sctp_tcb *stcb,
|
||||
htcp_reset(&net->cc_mod.htcp_ca);
|
||||
net->ssthresh = htcp_recalc_ssthresh(net);
|
||||
net->cwnd = net->ssthresh;
|
||||
sctp_enforce_cwnd_limit(asoc, net);
|
||||
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) {
|
||||
sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd),
|
||||
SCTP_CWND_LOG_FROM_FR);
|
||||
@ -2291,6 +2313,7 @@ sctp_htcp_cwnd_update_after_ecn_echo(struct sctp_tcb *stcb,
|
||||
net->RTO <<= 1;
|
||||
}
|
||||
net->cwnd = net->ssthresh;
|
||||
sctp_enforce_cwnd_limit(&stcb->asoc, net);
|
||||
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);
|
||||
}
|
||||
|
@ -2763,6 +2763,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
|
||||
inp->sctp_mobility_features = (*inp_p)->sctp_mobility_features;
|
||||
inp->sctp_socket = so;
|
||||
inp->sctp_frag_point = (*inp_p)->sctp_frag_point;
|
||||
inp->max_cwnd = (*inp_p)->max_cwnd;
|
||||
inp->sctp_cmt_on_off = (*inp_p)->sctp_cmt_on_off;
|
||||
inp->ecn_supported = (*inp_p)->ecn_supported;
|
||||
inp->prsctp_supported = (*inp_p)->prsctp_supported;
|
||||
|
@ -2474,6 +2474,7 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
|
||||
inp->sctp_associd_counter = 1;
|
||||
inp->partial_delivery_point = SCTP_SB_LIMIT_RCV(so) >> SCTP_PARTIAL_DELIVERY_SHIFT;
|
||||
inp->sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT;
|
||||
inp->max_cwnd = 0;
|
||||
inp->sctp_cmt_on_off = SCTP_BASE_SYSCTL(sctp_cmt_on_off);
|
||||
inp->ecn_supported = (uint8_t) SCTP_BASE_SYSCTL(sctp_ecn_enable);
|
||||
inp->prsctp_supported = (uint8_t) SCTP_BASE_SYSCTL(sctp_pr_enable);
|
||||
|
@ -404,6 +404,7 @@ struct sctp_inpcb {
|
||||
uint32_t sctp_frag_point;
|
||||
uint32_t partial_delivery_point;
|
||||
uint32_t sctp_context;
|
||||
uint32_t max_cwnd;
|
||||
uint8_t local_strreset_support;
|
||||
uint32_t sctp_cmt_on_off;
|
||||
uint8_t ecn_supported;
|
||||
|
@ -127,6 +127,7 @@ sctp_do_peeloff(struct socket *head, struct socket *so, sctp_assoc_t assoc_id)
|
||||
n_inp->pktdrop_supported = inp->pktdrop_supported;
|
||||
n_inp->partial_delivery_point = inp->partial_delivery_point;
|
||||
n_inp->sctp_context = inp->sctp_context;
|
||||
n_inp->max_cwnd = inp->max_cwnd;
|
||||
n_inp->local_strreset_support = inp->local_strreset_support;
|
||||
n_inp->inp_starting_point_for_iterator = NULL;
|
||||
/* copy in the authentication parameters from the original endpoint */
|
||||
|
@ -1199,6 +1199,7 @@ struct sctp_association {
|
||||
uint8_t sctp_cmt_pf;
|
||||
uint8_t use_precise_time;
|
||||
uint64_t sctp_features;
|
||||
uint32_t max_cwnd;
|
||||
uint16_t port; /* remote UDP encapsulation port */
|
||||
/*
|
||||
* The mapping array is used to track out of order sequences above
|
||||
|
@ -3694,6 +3694,33 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SCTP_MAX_CWND:
|
||||
{
|
||||
struct sctp_assoc_value *av;
|
||||
|
||||
SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
|
||||
SCTP_FIND_STCB(inp, stcb, av->assoc_id);
|
||||
|
||||
if (stcb) {
|
||||
av->assoc_value = stcb->asoc.max_cwnd;
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
} else {
|
||||
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
|
||||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
|
||||
(av->assoc_id == SCTP_FUTURE_ASSOC)) {
|
||||
SCTP_INP_RLOCK(inp);
|
||||
av->assoc_value = inp->max_cwnd;
|
||||
SCTP_INP_RUNLOCK(inp);
|
||||
} else {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
|
||||
error = EINVAL;
|
||||
}
|
||||
}
|
||||
if (error == 0) {
|
||||
*optsize = sizeof(struct sctp_assoc_value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
|
||||
error = ENOPROTOOPT;
|
||||
@ -6572,6 +6599,42 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SCTP_MAX_CWND:
|
||||
{
|
||||
struct sctp_assoc_value *av;
|
||||
struct sctp_nets *net;
|
||||
|
||||
SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
|
||||
SCTP_FIND_STCB(inp, stcb, av->assoc_id);
|
||||
|
||||
if (stcb) {
|
||||
stcb->asoc.max_cwnd = av->assoc_value;
|
||||
if (stcb->asoc.max_cwnd > 0) {
|
||||
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
|
||||
if ((net->cwnd > stcb->asoc.max_cwnd) &&
|
||||
(net->cwnd > (net->mtu - sizeof(struct sctphdr)))) {
|
||||
net->cwnd = stcb->asoc.max_cwnd;
|
||||
if (net->cwnd < (net->mtu - sizeof(struct sctphdr))) {
|
||||
net->cwnd = net->mtu - sizeof(struct sctphdr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
} else {
|
||||
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
|
||||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
|
||||
(av->assoc_id == SCTP_FUTURE_ASSOC)) {
|
||||
SCTP_INP_WLOCK(inp);
|
||||
inp->max_cwnd = av->assoc_value;
|
||||
SCTP_INP_WUNLOCK(inp);
|
||||
} else {
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
|
||||
error = EINVAL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
|
||||
error = ENOPROTOOPT;
|
||||
|
@ -936,6 +936,7 @@ sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
|
||||
asoc->sctp_frag_point = inp->sctp_frag_point;
|
||||
asoc->sctp_features = inp->sctp_features;
|
||||
asoc->default_dscp = inp->sctp_ep.default_dscp;
|
||||
asoc->max_cwnd = inp->max_cwnd;
|
||||
#ifdef INET6
|
||||
if (inp->sctp_ep.default_flowlabel) {
|
||||
asoc->default_flowlabel = inp->sctp_ep.default_flowlabel;
|
||||
|
Loading…
Reference in New Issue
Block a user