Author: tuexen
Date: Tue Mar 10 19:49:25 2015
New Revision: 279859
URL: https://svnweb.freebsd.org/changeset/base/279859

Log:
  Add a SCTP socket option to limit the cwnd for each path.
  
  MFC after: 1 month

Modified:
  head/lib/libc/net/sctp_sys_calls.c
  head/sys/netinet/sctp.h
  head/sys/netinet/sctp_cc_functions.c
  head/sys/netinet/sctp_input.c
  head/sys/netinet/sctp_pcb.c
  head/sys/netinet/sctp_pcb.h
  head/sys/netinet/sctp_peeloff.c
  head/sys/netinet/sctp_structs.h
  head/sys/netinet/sctp_usrreq.c
  head/sys/netinet/sctputil.c

Modified: head/lib/libc/net/sctp_sys_calls.c
==============================================================================
--- head/lib/libc/net/sctp_sys_calls.c  Tue Mar 10 19:17:40 2015        
(r279858)
+++ head/lib/libc/net/sctp_sys_calls.c  Tue Mar 10 19:49:25 2015        
(r279859)
@@ -383,6 +383,9 @@ sctp_opt_info(int sd, sctp_assoc_t id, i
        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;
        }

Modified: head/sys/netinet/sctp.h
==============================================================================
--- head/sys/netinet/sctp.h     Tue Mar 10 19:17:40 2015        (r279858)
+++ head/sys/netinet/sctp.h     Tue Mar 10 19:49:25 2015        (r279859)
@@ -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

Modified: head/sys/netinet/sctp_cc_functions.c
==============================================================================
--- head/sys/netinet/sctp_cc_functions.c        Tue Mar 10 19:17:40 2015        
(r279858)
+++ head/sys/netinet/sctp_cc_functions.c        Tue Mar 10 19:49:25 2015        
(r279859)
@@ -53,6 +53,19 @@ __FBSDID("$FreeBSD$");
 #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)
 {
        struct sctp_association *assoc;
@@ -80,6 +93,7 @@ sctp_set_initial_cc_param(struct sctp_tc
                        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_tc
                                        }
                                }
                                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, st
                        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, st
                        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, st
                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(struc
                                                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(struc
                                                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(st
                /* 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 sct
                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 *s
                /* 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 *s
                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 *s
                        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 sc
                        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 sc
                                    (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, s
                                            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, s
                         */
                        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 sc
         */
        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 sc
                                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(str
                        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);
                }

Modified: head/sys/netinet/sctp_input.c
==============================================================================
--- head/sys/netinet/sctp_input.c       Tue Mar 10 19:17:40 2015        
(r279858)
+++ head/sys/netinet/sctp_input.c       Tue Mar 10 19:49:25 2015        
(r279859)
@@ -2763,6 +2763,7 @@ sctp_handle_cookie_echo(struct mbuf *m, 
                        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;

Modified: head/sys/netinet/sctp_pcb.c
==============================================================================
--- head/sys/netinet/sctp_pcb.c Tue Mar 10 19:17:40 2015        (r279858)
+++ head/sys/netinet/sctp_pcb.c Tue Mar 10 19:49:25 2015        (r279859)
@@ -2474,6 +2474,7 @@ sctp_inpcb_alloc(struct socket *so, uint
        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);

Modified: head/sys/netinet/sctp_pcb.h
==============================================================================
--- head/sys/netinet/sctp_pcb.h Tue Mar 10 19:17:40 2015        (r279858)
+++ head/sys/netinet/sctp_pcb.h Tue Mar 10 19:49:25 2015        (r279859)
@@ -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;

Modified: head/sys/netinet/sctp_peeloff.c
==============================================================================
--- head/sys/netinet/sctp_peeloff.c     Tue Mar 10 19:17:40 2015        
(r279858)
+++ head/sys/netinet/sctp_peeloff.c     Tue Mar 10 19:49:25 2015        
(r279859)
@@ -127,6 +127,7 @@ sctp_do_peeloff(struct socket *head, str
        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 */

Modified: head/sys/netinet/sctp_structs.h
==============================================================================
--- head/sys/netinet/sctp_structs.h     Tue Mar 10 19:17:40 2015        
(r279858)
+++ head/sys/netinet/sctp_structs.h     Tue Mar 10 19:49:25 2015        
(r279859)
@@ -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

Modified: head/sys/netinet/sctp_usrreq.c
==============================================================================
--- head/sys/netinet/sctp_usrreq.c      Tue Mar 10 19:17:40 2015        
(r279858)
+++ head/sys/netinet/sctp_usrreq.c      Tue Mar 10 19:49:25 2015        
(r279859)
@@ -3694,6 +3694,33 @@ flags_out:
                        }
                        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 optna
                        }
                        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;

Modified: head/sys/netinet/sctputil.c
==============================================================================
--- head/sys/netinet/sctputil.c Tue Mar 10 19:17:40 2015        (r279858)
+++ head/sys/netinet/sctputil.c Tue Mar 10 19:49:25 2015        (r279859)
@@ -936,6 +936,7 @@ sctp_init_asoc(struct sctp_inpcb *inp, s
        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;
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to