summaryrefslogtreecommitdiffstats
path: root/sys/netinet/sctp_indata.c
diff options
context:
space:
mode:
authorrrs <rrs@FreeBSD.org>2007-07-14 09:36:28 +0000
committerrrs <rrs@FreeBSD.org>2007-07-14 09:36:28 +0000
commit1e9af2c480a638933876e637c1f3b9f1b7bad3e9 (patch)
tree008308315d74a9df2eec618692844a82f1ace245 /sys/netinet/sctp_indata.c
parent0948603d9eefb8b7f5898f99c8703b2e5b7f9647 (diff)
downloadFreeBSD-src-1e9af2c480a638933876e637c1f3b9f1b7bad3e9.zip
FreeBSD-src-1e9af2c480a638933876e637c1f3b9f1b7bad3e9.tar.gz
- Modular congestion control, with RFC2581 being the default.
- CMT_PF states added (w/sysctl to turn the PF version on) - sctp_input.c had a missing incr of cookie case when the auth was bad. This meant a free was called without an increment to refcnt, added increment like rest of code. - There was a case, unlikely, when the scope of the destination changed (this is a TSNH case). In that case, it would not free the alloc'ed asoc (in sctp_input.c). - When listed addresses found a colliding cookie/Init, then the collided upon tcb was not unlocked in sctp_pcb.c - Add error checking on arguments of sctp_sendx(3) to prevent it from referencing a NULL pointer. - Fix an error return of sctp_sendx(3), it was returing ENOMEM not -1. - Get assoc id was changed to use the sanctified socket api method for getting a assoc id (PEER_ADDR_INFO instead of PEER_ADDR_PARAMS). - Fix it so a peeled off socket will get a proper error return if it trys to send to a different address then it is connected to. - Fix so that select_a_stream can avoid an endless loop that could hang a caller. - time_entered (state set time) was not being set in all cases to the time we went established. Approved by: re(ken smith)
Diffstat (limited to 'sys/netinet/sctp_indata.c')
-rw-r--r--sys/netinet/sctp_indata.c490
1 files changed, 21 insertions, 469 deletions
diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c
index 06fcddc..0d8bbac 100644
--- a/sys/netinet/sctp_indata.c
+++ b/sys/netinet/sctp_indata.c
@@ -3456,7 +3456,21 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc,
tp1->no_fr_allowed = 1;
alt = tp1->whoTo;
/* sa_ignore NO_NULL_CHK */
- alt = sctp_find_alternate_net(stcb, alt, 1);
+ if (sctp_cmt_pf) {
+ /*
+ * JRS 5/18/07 - If CMT PF is on,
+ * use the PF version of
+ * find_alt_net()
+ */
+ alt = sctp_find_alternate_net(stcb, alt, 2);
+ } else {
+ /*
+ * JRS 5/18/07 - If only CMT is on,
+ * use the CMT version of
+ * find_alt_net()
+ */
+ alt = sctp_find_alternate_net(stcb, alt, 1);
+ }
if (alt == NULL) {
alt = tp1->whoTo;
}
@@ -3675,387 +3689,6 @@ sctp_try_advance_peer_ack_point(struct sctp_tcb *stcb,
return (a_adv);
}
-#ifdef SCTP_HIGH_SPEED
-struct sctp_hs_raise_drop {
- int32_t cwnd;
- int32_t increase;
- int32_t drop_percent;
-};
-
-#define SCTP_HS_TABLE_SIZE 73
-
-struct sctp_hs_raise_drop sctp_cwnd_adjust[SCTP_HS_TABLE_SIZE] = {
- {38, 1, 50}, /* 0 */
- {118, 2, 44}, /* 1 */
- {221, 3, 41}, /* 2 */
- {347, 4, 38}, /* 3 */
- {495, 5, 37}, /* 4 */
- {663, 6, 35}, /* 5 */
- {851, 7, 34}, /* 6 */
- {1058, 8, 33}, /* 7 */
- {1284, 9, 32}, /* 8 */
- {1529, 10, 31}, /* 9 */
- {1793, 11, 30}, /* 10 */
- {2076, 12, 29}, /* 11 */
- {2378, 13, 28}, /* 12 */
- {2699, 14, 28}, /* 13 */
- {3039, 15, 27}, /* 14 */
- {3399, 16, 27}, /* 15 */
- {3778, 17, 26}, /* 16 */
- {4177, 18, 26}, /* 17 */
- {4596, 19, 25}, /* 18 */
- {5036, 20, 25}, /* 19 */
- {5497, 21, 24}, /* 20 */
- {5979, 22, 24}, /* 21 */
- {6483, 23, 23}, /* 22 */
- {7009, 24, 23}, /* 23 */
- {7558, 25, 22}, /* 24 */
- {8130, 26, 22}, /* 25 */
- {8726, 27, 22}, /* 26 */
- {9346, 28, 21}, /* 27 */
- {9991, 29, 21}, /* 28 */
- {10661, 30, 21}, /* 29 */
- {11358, 31, 20}, /* 30 */
- {12082, 32, 20}, /* 31 */
- {12834, 33, 20}, /* 32 */
- {13614, 34, 19}, /* 33 */
- {14424, 35, 19}, /* 34 */
- {15265, 36, 19}, /* 35 */
- {16137, 37, 19}, /* 36 */
- {17042, 38, 18}, /* 37 */
- {17981, 39, 18}, /* 38 */
- {18955, 40, 18}, /* 39 */
- {19965, 41, 17}, /* 40 */
- {21013, 42, 17}, /* 41 */
- {22101, 43, 17}, /* 42 */
- {23230, 44, 17}, /* 43 */
- {24402, 45, 16}, /* 44 */
- {25618, 46, 16}, /* 45 */
- {26881, 47, 16}, /* 46 */
- {28193, 48, 16}, /* 47 */
- {29557, 49, 15}, /* 48 */
- {30975, 50, 15}, /* 49 */
- {32450, 51, 15}, /* 50 */
- {33986, 52, 15}, /* 51 */
- {35586, 53, 14}, /* 52 */
- {37253, 54, 14}, /* 53 */
- {38992, 55, 14}, /* 54 */
- {40808, 56, 14}, /* 55 */
- {42707, 57, 13}, /* 56 */
- {44694, 58, 13}, /* 57 */
- {46776, 59, 13}, /* 58 */
- {48961, 60, 13}, /* 59 */
- {51258, 61, 13}, /* 60 */
- {53677, 62, 12}, /* 61 */
- {56230, 63, 12}, /* 62 */
- {58932, 64, 12}, /* 63 */
- {61799, 65, 12}, /* 64 */
- {64851, 66, 11}, /* 65 */
- {68113, 67, 11}, /* 66 */
- {71617, 68, 11}, /* 67 */
- {75401, 69, 10}, /* 68 */
- {79517, 70, 10}, /* 69 */
- {84035, 71, 10}, /* 70 */
- {89053, 72, 10}, /* 71 */
- {94717, 73, 9} /* 72 */
-};
-
-static void
-sctp_hs_cwnd_increase(struct sctp_tcb *stcb, struct sctp_nets *net)
-{
- int cur_val, i, indx, incr;
-
- cur_val = net->cwnd >> 10;
- indx = SCTP_HS_TABLE_SIZE - 1;
-
- if (cur_val < sctp_cwnd_adjust[0].cwnd) {
- /* normal mode */
- if (net->net_ack > net->mtu) {
- net->cwnd += net->mtu;
- if (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_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++) {
- if (cur_val < sctp_cwnd_adjust[i].cwnd) {
- indx = i;
- break;
- }
- }
- net->last_hs_used = indx;
- incr = ((sctp_cwnd_adjust[indx].increase) << 10);
- net->cwnd += incr;
- if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) {
- sctp_log_cwnd(stcb, net, incr, SCTP_CWND_LOG_FROM_SS);
- }
- }
-}
-
-static void
-sctp_hs_cwnd_decrease(struct sctp_tcb *stcb, struct sctp_nets *net)
-{
- int cur_val, i, indx;
- int old_cwnd = net->cwnd;
-
- cur_val = net->cwnd >> 10;
- indx = net->last_hs_used;
- if (cur_val < sctp_cwnd_adjust[0].cwnd) {
- /* normal mode */
- net->ssthresh = net->cwnd / 2;
- if (net->ssthresh < (net->mtu * 2)) {
- net->ssthresh = 2 * net->mtu;
- }
- net->cwnd = net->ssthresh;
- } else {
- /* drop by the proper amount */
- net->ssthresh = net->cwnd - (int)((net->cwnd / 100) *
- sctp_cwnd_adjust[net->last_hs_used].drop_percent);
- net->cwnd = net->ssthresh;
- /* now where are we */
- indx = net->last_hs_used;
- cur_val = net->cwnd >> 10;
- /* reset where we are in the table */
- if (cur_val < sctp_cwnd_adjust[0].cwnd) {
- /* feel out of hs */
- net->last_hs_used = 0;
- } else {
- for (i = indx; i >= 1; i--) {
- if (cur_val > sctp_cwnd_adjust[i - 1].cwnd) {
- break;
- }
- }
- net->last_hs_used = indx;
- }
- }
- if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) {
- sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd), SCTP_CWND_LOG_FROM_FR);
- }
-}
-
-#endif
-
-
-static void
-sctp_cwnd_update(struct sctp_tcb *stcb,
- struct sctp_association *asoc,
- int accum_moved, int reneged_all, int will_exit)
-{
- struct sctp_nets *net;
-
- /******************************/
- /* update cwnd and Early FR */
- /******************************/
- TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
-
-#ifdef JANA_CMT_FAST_RECOVERY
- /*
- * CMT fast recovery code. Need to debug.
- */
- if (net->fast_retran_loss_recovery && net->new_pseudo_cumack) {
- if (compare_with_wrap(asoc->last_acked_seq,
- net->fast_recovery_tsn, MAX_TSN) ||
- (asoc->last_acked_seq == net->fast_recovery_tsn) ||
- compare_with_wrap(net->pseudo_cumack, net->fast_recovery_tsn, MAX_TSN) ||
- (net->pseudo_cumack == net->fast_recovery_tsn)) {
- net->will_exit_fast_recovery = 1;
- }
- }
-#endif
- if (sctp_early_fr) {
- /*
- * So, first of all do we need to have a Early FR
- * timer running?
- */
- if (((TAILQ_FIRST(&asoc->sent_queue)) &&
- (net->ref_count > 1) &&
- (net->flight_size < net->cwnd)) ||
- (reneged_all)) {
- /*
- * yes, so in this case stop it if its
- * running, and then restart it. Reneging
- * all is a special case where we want to
- * run the Early FR timer and then force the
- * last few unacked to be sent, causing us
- * to illicit a sack with gaps to force out
- * the others.
- */
- if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
- SCTP_STAT_INCR(sctps_earlyfrstpidsck2);
- sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
- SCTP_FROM_SCTP_INDATA + SCTP_LOC_20);
- }
- SCTP_STAT_INCR(sctps_earlyfrstrid);
- sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net);
- } else {
- /* No, stop it if its running */
- if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) {
- SCTP_STAT_INCR(sctps_earlyfrstpidsck3);
- sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, stcb->sctp_ep, stcb, net,
- SCTP_FROM_SCTP_INDATA + SCTP_LOC_21);
- }
- }
- }
- /* if nothing was acked on this destination skip it */
- if (net->net_ack == 0) {
- if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) {
- sctp_log_cwnd(stcb, net, 0, SCTP_CWND_LOG_FROM_SACK);
- }
- continue;
- }
- if (net->net_ack2 > 0) {
- /*
- * Karn's rule applies to clearing error count, this
- * is optional.
- */
- net->error_count = 0;
- if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) ==
- SCTP_ADDR_NOT_REACHABLE) {
- /* addr came good */
- net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE;
- net->dest_state |= SCTP_ADDR_REACHABLE;
- sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
- SCTP_RECEIVED_SACK, (void *)net);
- /* now was it the primary? if so restore */
- if (net->dest_state & SCTP_ADDR_WAS_PRIMARY) {
- (void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net);
- }
- }
- }
-#ifdef JANA_CMT_FAST_RECOVERY
- /*
- * CMT fast recovery code
- */
- /*
- * if (sctp_cmt_on_off == 1 &&
- * net->fast_retran_loss_recovery &&
- * net->will_exit_fast_recovery == 0) { // @@@ Do something
- * } else if (sctp_cmt_on_off == 0 &&
- * asoc->fast_retran_loss_recovery && will_exit == 0) {
- */
-#endif
-
- if (asoc->fast_retran_loss_recovery && will_exit == 0 && sctp_cmt_on_off == 0) {
- /*
- * If we are in loss recovery we skip any cwnd
- * update
- */
- goto skip_cwnd_update;
- }
- /*
- * CMT: CUC algorithm. Update cwnd if pseudo-cumack has
- * moved.
- */
- if (accum_moved || (sctp_cmt_on_off && net->new_pseudo_cumack)) {
- /* If the cumulative ack moved we can proceed */
- if (net->cwnd <= net->ssthresh) {
- /* We are in slow start */
- if (net->flight_size + net->net_ack >=
- net->cwnd) {
-#ifdef SCTP_HIGH_SPEED
- sctp_hs_cwnd_increase(stcb, net);
-#else
- if (net->net_ack > (net->mtu * sctp_L2_abc_variable)) {
- net->cwnd += (net->mtu * sctp_L2_abc_variable);
- if (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;
- sctp_log_cwnd(stcb, net, net->net_ack,
- SCTP_CWND_LOG_FROM_SS);
- }
-#endif
- } else {
- unsigned int dif;
-
- dif = net->cwnd - (net->flight_size +
- net->net_ack);
- if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) {
- sctp_log_cwnd(stcb, net, net->net_ack,
- SCTP_CWND_LOG_NOADV_SS);
- }
- }
- } else {
- /* We are in congestion avoidance */
- if (net->flight_size + net->net_ack >=
- net->cwnd) {
- /*
- * add to pba only if we had a
- * cwnd's worth (or so) in flight OR
- * the burst limit was applied.
- */
- net->partial_bytes_acked +=
- net->net_ack;
-
- /*
- * Do we need to increase (if pba is
- * > cwnd)?
- */
- if (net->partial_bytes_acked >=
- net->cwnd) {
- if (net->cwnd <
- net->partial_bytes_acked) {
- net->partial_bytes_acked -=
- net->cwnd;
- } else {
- net->partial_bytes_acked =
- 0;
- }
- net->cwnd += net->mtu;
- if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) {
- sctp_log_cwnd(stcb, net, net->mtu,
- SCTP_CWND_LOG_FROM_CA);
- }
- } else {
- if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) {
- sctp_log_cwnd(stcb, net, net->net_ack,
- SCTP_CWND_LOG_NOADV_CA);
- }
- }
- } else {
- unsigned int dif;
-
- if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) {
- sctp_log_cwnd(stcb, net, net->net_ack,
- SCTP_CWND_LOG_NOADV_CA);
- }
- dif = net->cwnd - (net->flight_size +
- net->net_ack);
- }
- }
- } else {
- if (sctp_logging_level & SCTP_CWND_LOGGING_ENABLE) {
- sctp_log_cwnd(stcb, net, net->mtu,
- SCTP_CWND_LOG_NO_CUMACK);
- }
- }
-skip_cwnd_update:
- /*
- * NOW, according to Karn's rule do we need to restore the
- * RTO timer back? Check our net_ack2. If not set then we
- * have a ambiguity.. i.e. all data ack'd was sent to more
- * than one place.
- */
- if (net->net_ack2) {
- /* restore any doubled timers */
- net->RTO = ((net->lastsa >> 2) + net->lastsv) >> 1;
- if (net->RTO < stcb->asoc.minrto) {
- net->RTO = stcb->asoc.minrto;
- }
- if (net->RTO > stcb->asoc.maxrto) {
- net->RTO = stcb->asoc.maxrto;
- }
- }
- }
-}
-
static void
sctp_fs_audit(struct sctp_association *asoc)
{
@@ -4130,7 +3763,6 @@ sctp_window_probe_recovery(struct sctp_tcb *stcb,
}
}
-
void
sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
uint32_t rwnd, int nonce_sum_flag, int *abort_now)
@@ -4342,9 +3974,9 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
}
}
-
+ /* JRS - Use the congestion control given in the CC module */
if (asoc->last_acked_seq != cumack)
- sctp_cwnd_update(stcb, asoc, 1, 0, 0);
+ asoc->cc_functions.sctp_cwnd_update_after_sack(stcb, asoc, 1, 0, 0);
asoc->last_acked_seq = cumack;
@@ -4578,8 +4210,6 @@ again:
}
}
-
-
void
sctp_handle_sack(struct mbuf *m, int offset,
struct sctp_sack_chunk *ch, struct sctp_tcb *stcb,
@@ -5116,8 +4746,8 @@ done_with_it:
else
asoc->saw_sack_with_frags = 0;
-
- sctp_cwnd_update(stcb, asoc, accum_moved, reneged_all, will_exit_fast_recovery);
+ /* JRS - Use the congestion control given in the CC module */
+ asoc->cc_functions.sctp_cwnd_update_after_sack(stcb, asoc, accum_moved, reneged_all, will_exit_fast_recovery);
if (TAILQ_EMPTY(&asoc->sent_queue)) {
/* nothing left in-flight */
@@ -5286,86 +4916,8 @@ done_with_it:
}
}
}
- /*
- * CMT fast recovery code. Need to debug. ((sctp_cmt_on_off == 1) &&
- * (net->fast_retran_loss_recovery == 0)))
- */
- TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
- if ((asoc->fast_retran_loss_recovery == 0) || (sctp_cmt_on_off == 1)) {
- /* out of a RFC2582 Fast recovery window? */
- if (net->net_ack > 0) {
- /*
- * per section 7.2.3, are there any
- * destinations that had a fast retransmit
- * to them. If so what we need to do is
- * adjust ssthresh and cwnd.
- */
- struct sctp_tmit_chunk *lchk;
-
-#ifdef SCTP_HIGH_SPEED
- sctp_hs_cwnd_decrease(stcb, net);
-#else
- int old_cwnd = net->cwnd;
-
- net->ssthresh = net->cwnd / 2;
- if (net->ssthresh < (net->mtu * 2)) {
- net->ssthresh = 2 * net->mtu;
- }
- net->cwnd = net->ssthresh;
- if (sctp_logging_level & SCTP_CWND_MONITOR_ENABLE) {
- sctp_log_cwnd(stcb, net, (net->cwnd - old_cwnd),
- SCTP_CWND_LOG_FROM_FR);
- }
-#endif
-
- lchk = TAILQ_FIRST(&asoc->send_queue);
-
- net->partial_bytes_acked = 0;
- /* Turn on fast recovery window */
- asoc->fast_retran_loss_recovery = 1;
- if (lchk == NULL) {
- /* Mark end of the window */
- asoc->fast_recovery_tsn = asoc->sending_seq - 1;
- } else {
- asoc->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1;
- }
-
- /*
- * CMT fast recovery -- per destination
- * recovery variable.
- */
- net->fast_retran_loss_recovery = 1;
-
- if (lchk == NULL) {
- /* Mark end of the window */
- net->fast_recovery_tsn = asoc->sending_seq - 1;
- } else {
- net->fast_recovery_tsn = lchk->rec.data.TSN_seq - 1;
- }
-
-
-
- /*
- * Disable Nonce Sum Checking and store the
- * resync tsn
- */
- asoc->nonce_sum_check = 0;
- asoc->nonce_resync_tsn = asoc->fast_recovery_tsn + 1;
-
- sctp_timer_stop(SCTP_TIMER_TYPE_SEND,
- stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INDATA + SCTP_LOC_32);
- sctp_timer_start(SCTP_TIMER_TYPE_SEND,
- stcb->sctp_ep, stcb, net);
- }
- } else if (net->net_ack > 0) {
- /*
- * Mark a peg that we WOULD have done a cwnd
- * reduction but RFC2582 prevented this action.
- */
- SCTP_STAT_INCR(sctps_fastretransinrtt);
- }
- }
-
+ /* JRS - Use the congestion control given in the CC module */
+ asoc->cc_functions.sctp_cwnd_update_after_fr(stcb, asoc);
/******************************************************************
* Here we do the stuff with ECN Nonce checking.
OpenPOWER on IntegriCloud